• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2019 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
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 /**
25  * \file  gl2fClipControlTests.cpp
26  * \brief Implements conformance tests for "EXT_clip_control" functionality.
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "es2fClipControlTests.hpp"
30 
31 #include "deSharedPtr.hpp"
32 
33 #include "gluContextInfo.hpp"
34 #include "gluDrawUtil.hpp"
35 #include "gluDefs.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluShaderProgram.hpp"
38 
39 #include "tcuFuzzyImageCompare.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuRenderTarget.hpp"
42 #include "tcuSurface.hpp"
43 #include "tcuTestLog.hpp"
44 
45 #include "glw.h"
46 #include "glwFunctions.hpp"
47 
48 #include <cmath>
49 
50 namespace deqp
51 {
52 namespace gles2
53 {
54 namespace Functional
55 {
56 
57 class ClipControlApi
58 {
59 public:
ClipControlApi(Context & context)60 	ClipControlApi(Context& context) : m_context(context)
61 	{
62 		if (!Supported(m_context))
63 		{
64 			throw tcu::NotSupportedError("Required extension EXT_clip_control is not supported");
65 		}
66 		clipControl = context.getRenderContext().getFunctions().clipControl;
67 	}
68 
Supported(Context & context)69 	static bool Supported(Context& context)
70 	{
71 		return context.getContextInfo().isExtensionSupported("GL_EXT_clip_control");
72 	}
73 
74 	glw::glClipControlFunc clipControl;
75 
76 private:
77 	Context& m_context;
78 };
79 
80 class ClipControlBaseTest : public TestCase
81 {
82 protected:
ClipControlBaseTest(Context & context,const char * name,const char * description)83 	ClipControlBaseTest(Context& context, const char* name, const char* description)
84 		: TestCase(context, name, description)
85 	{
86 	}
87 
init()88 	void init() override
89 	{
90 		ClipControlApi api(m_context);
91 	}
92 
verifyState(glw::GLenum origin,glw::GLenum depth)93 	bool verifyState(glw::GLenum origin, glw::GLenum depth)
94 	{
95 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
96 
97 		bool ret = true;
98 
99 		glw::GLint retI;
100 		gl.getIntegerv(GL_CLIP_ORIGIN, &retI);
101 		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_CLIP_ORIGIN");
102 
103 		ret &= (static_cast<glw::GLenum>(retI) == origin);
104 
105 		gl.getIntegerv(GL_CLIP_DEPTH_MODE, &retI);
106 		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_CLIP_DEPTH_MODE");
107 
108 		ret &= (static_cast<glw::GLenum>(retI) == depth);
109 
110 		return ret;
111 	}
112 };
113 
114 class ClipControlRenderBaseTest : public ClipControlBaseTest
115 {
116 protected:
ClipControlRenderBaseTest(Context & context,const char * name,const char * description)117 	ClipControlRenderBaseTest(Context& context, const char* name, const char* description)
118 		: ClipControlBaseTest(context, name, description), m_fbo(0), m_rboC(0), m_depthTexure(0)
119 	{
120 	}
121 
fsh()122 	const char* fsh()
123 	{
124 		return "void main() {"
125 			   "\n"
126 			   "    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);"
127 			   "\n"
128 			   "}";
129 	}
130 
fuzzyDepthCompare(tcu::TestLog & log,const char * imageSetName,const char * imageSetDesc,const tcu::TextureLevel & reference,const tcu::TextureLevel & result,float threshold,const tcu::TextureLevel * importanceMask=NULL)131 	bool fuzzyDepthCompare(tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc,
132 						   const tcu::TextureLevel& reference, const tcu::TextureLevel& result, float threshold,
133 						   const tcu::TextureLevel* importanceMask = NULL)
134 	{
135 		(void)imageSetName;
136 		(void)imageSetDesc;
137 		bool  depthOk	= true;
138 		float difference = 0.0f;
139 
140 		for (int y = 0; y < result.getHeight() && depthOk; y++)
141 		{
142 			for (int x = 0; x < result.getWidth() && depthOk; x++)
143 			{
144 				float ref  = reference.getAccess().getPixDepth(x, y);
145 				float res  = result.getAccess().getPixel(x,y).x();
146 				difference = std::abs(ref - res);
147 				if (importanceMask)
148 				{
149 					difference *= importanceMask->getAccess().getPixDepth(x, y);
150 				}
151 				depthOk &= (difference < threshold);
152 			}
153 		}
154 
155 		if (!depthOk)
156 			log << tcu::TestLog::Message << "Image comparison failed: difference = " << difference
157 				<< ", threshold = " << threshold << tcu::TestLog::EndMessage;
158 		tcu::Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
159 		tcu::Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
160 		log << tcu::TestLog::ImageSet("Result", "Depth image comparison result")
161 			<< tcu::TestLog::Image("Result", "Result", result.getAccess(), pixelScale, pixelBias)
162 			<< tcu::TestLog::Image("Reference", "Reference", reference.getAccess(), pixelScale, pixelBias);
163 		if (importanceMask)
164 		{
165 			log << tcu::TestLog::Image("Importance mask", "mask", importanceMask->getAccess(), pixelScale, pixelBias);
166 		}
167 		log << tcu::TestLog::EndImageSet;
168 
169 		return depthOk;
170 	}
171 
init(void)172 	virtual void init(void)
173 	{
174 		const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
175 		glw::GLuint				 viewportW	= renderTarget.getWidth();
176 		glw::GLuint				 viewportH	= renderTarget.getHeight();
177 		const glw::Functions&	gl			  = m_context.getRenderContext().getFunctions();
178 
179 		gl.genFramebuffers(1, &m_fbo);
180 		gl.genRenderbuffers(1, &m_rboC);
181 		gl.genTextures(1, &m_depthTexure);
182 
183 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_rboC);
184 		gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, viewportW, viewportH);
185 
186 		gl.bindTexture(GL_TEXTURE_2D, m_depthTexure);
187 		gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewportW, viewportH, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, DE_NULL);
188 
189 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
190 		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rboC);
191 		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexure, 0);
192 	}
193 
deinit(void)194 	virtual void deinit(void)
195 	{
196 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
197 		gl.deleteFramebuffers(1, &m_fbo);
198 		gl.deleteRenderbuffers(1, &m_rboC);
199 		gl.deleteTextures(1, &m_depthTexure);
200 		gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
201 	}
202 
getDepthTexture()203 	GLuint getDepthTexture()
204 	{
205 		return m_depthTexure;
206 	}
207 
208 private:
209 	GLuint m_fbo, m_rboC, m_depthTexure;
210 };
211 
212 /*
213  Verify the following state values are implemented and return a valid
214  initial value by calling GetIntegerv:
215 
216  Get Value                                 Initial Value
217  -------------------------------------------------------
218  CLIP_ORIGIN                                  LOWER_LEFT
219  CLIP_DEPTH_MODE                     NEGATIVE_ONE_TO_ONE
220 
221  Verify no GL error is generated.
222  */
223 class ClipControlInitialState : public ClipControlBaseTest
224 {
225 public:
ClipControlInitialState(Context & context,const char * name)226 	ClipControlInitialState(Context& context, const char* name)
227 		: ClipControlBaseTest(context, name, "Verify initial state")
228 	{
229 	}
230 
iterate()231 	IterateResult iterate() override
232 	{
233 		if (!verifyState(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE))
234 		{
235 			TCU_FAIL("Wrong intitial state: GL_CLIP_ORIGIN should be GL_LOWER_LEFT,"
236 					 " GL_CLIP_ORIGIN should be NEGATIVE_ONE_TO_ONE");
237 		}
238 
239 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
240 		return STOP;
241 	}
242 };
243 
244 /*
245  Modify the state to each of the following combinations and after each
246  state change verify the state values:
247 
248  ClipControl(UPPER_LEFT, ZERO_TO_ONE)
249  ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
250  ClipControl(LOWER_LEFT, ZERO_TO_ONE)
251  ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE)
252 
253  Verify no GL error is generated.
254 
255  */
256 class ClipControlModifyGetState : public ClipControlBaseTest
257 {
258 public:
ClipControlModifyGetState(Context & context,const char * name)259 	ClipControlModifyGetState(Context& context, const char* name)
260 		: ClipControlBaseTest(context,  name, "Verify initial state")
261 	{
262 	}
263 
deinit()264 	void deinit() override
265 	{
266 		if (ClipControlApi::Supported(m_context))
267 		{
268 			ClipControlApi cc(m_context);
269 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
270 		}
271 	}
272 
iterate()273 	IterateResult iterate() override
274 	{
275 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
276 		ClipControlApi		  cc(m_context);
277 
278 		GLenum cases[4][2] = {
279 			{ GL_UPPER_LEFT, GL_ZERO_TO_ONE },
280 			{ GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE },
281 			{ GL_LOWER_LEFT, GL_ZERO_TO_ONE },
282 			{ GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE },
283 		};
284 
285 		for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(cases); i++)
286 		{
287 			cc.clipControl(cases[i][0], cases[i][1]);
288 			GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
289 			if (!verifyState(cases[i][0], cases[i][1]))
290 			{
291 				TCU_FAIL("Wrong ClipControl state after ClipControl() call");
292 			}
293 		}
294 
295 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
296 		return STOP;
297 	}
298 };
299 
300 /*
301  Check that ClipControl generate an GL_INVALID_ENUM error if origin is
302  not GL_LOWER_LEFT or GL_UPPER_LEFT.
303 
304  Check that ClipControl generate an GL_INVALID_ENUM error if depth is
305  not GL_NEGATIVE_ONE_TO_ONE or GL_ZERO_TO_ONE.
306 
307  Test is based on OpenGL 4.5 Core Profile Specification May 28th Section
308  13.5 Primitive Clipping:
309  "An INVALID_ENUM error is generated if origin is not LOWER_LEFT or
310  UPPER_LEFT.
311  An INVALID_ENUM error is generated if depth is not NEGATIVE_ONE_-
312  TO_ONE or ZERO_TO_ONE."
313  */
314 class ClipControlErrors : public ClipControlBaseTest
315 {
316 public:
ClipControlErrors(Context & context,const char * name)317 	ClipControlErrors(Context& context, const char* name)
318 		: ClipControlBaseTest(context, name, "Verify that proper errors are generated when using ClipControl.")
319 	{
320 	}
321 
deinit()322 	void deinit() override
323 	{
324 		if (ClipControlApi::Supported(m_context))
325 		{
326 			ClipControlApi cc(m_context);
327 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
328 		}
329 	}
330 
iterate()331 	IterateResult iterate() override
332 	{
333 		/* API query */
334 		tcu::TestLog&		  log = m_testCtx.getLog();
335 		const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
336 		ClipControlApi		  cc(m_context);
337 
338 		/* Finding improper value. */
339 		GLenum improper_value = GL_NONE;
340 
341 		while ((GL_UPPER_LEFT == improper_value) || (GL_LOWER_LEFT == improper_value) ||
342 			   (GL_ZERO_TO_ONE == improper_value) || (GL_NEGATIVE_ONE_TO_ONE == improper_value))
343 		{
344 			++improper_value;
345 		}
346 
347 		/* Test setup. */
348 		GLenum cases[5][2] = { { GL_UPPER_LEFT, improper_value },
349 							   { GL_LOWER_LEFT, improper_value },
350 							   { improper_value, GL_ZERO_TO_ONE },
351 							   { improper_value, GL_NEGATIVE_ONE_TO_ONE },
352 							   { improper_value, improper_value } };
353 
354 		/* Test iterations. */
355 		for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(cases); i++)
356 		{
357 			cc.clipControl(cases[i][0], cases[i][1]);
358 
359 			if (GL_INVALID_ENUM != gl.getError())
360 			{
361 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
362 
363 				log << tcu::TestLog::Message
364 					<< "ClipControl have not generated GL_INVALID_ENUM error when called with invalid value ("
365 					<< cases[i][0] << ", " << cases[i][1] << ")." << tcu::TestLog::EndMessage;
366 			}
367 		}
368 
369 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
370 		return STOP;
371 	}
372 };
373 
374 /*
375  Clip Control Origin Test
376 
377  * Basic <origin> behavior can be tested by rendering to a viewport with
378  clip coordinates where -1.0 <= x_c <= 0.0 and -1.0 <= y_c <= 0.0.
379  When <origin> is LOWER_LEFT the "bottom left" portion of the window
380  is rendered and when UPPER_LEFT is used the "top left" portion of the
381  window is rendered. The default framebuffer should be bound. Here is the
382  basic outline of the test:
383 
384  - Clear the default framebuffer to red (1,0,0).
385  - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
386  - Render a triangle fan covering (-1.0, -1.0) to (0.0, 0.0) and
387  write a pixel value of green (0,1,0).
388  - Read back the default framebuffer with ReadPixels
389  - Verify the green pixels at the top and red at the bottom.
390 
391  Repeat the above test with LOWER_LEFT and verify green at the bottom
392  and red at the top.
393  */
394 class ClipControlOriginTest : public ClipControlRenderBaseTest
395 {
396 public:
ClipControlOriginTest(Context & context,const char * name)397 	ClipControlOriginTest(Context& context, const char* name)
398 		: ClipControlRenderBaseTest(context,  name, "Clip Control Origin Test"), m_vao(0), m_vbo(0)
399 	{
400 	}
401 
deinit()402 	void deinit() override
403 	{
404 		ClipControlRenderBaseTest::deinit();
405 
406 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
407 		if (ClipControlApi::Supported(m_context))
408 		{
409 			ClipControlApi cc(m_context);
410 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
411 		}
412 
413 		gl.clearColor(0.0, 0.0, 0.0, 0.0);
414 		if (m_vao)
415 		{
416 			gl.deleteVertexArrays(1, &m_vao);
417 		}
418 		if (m_vbo)
419 		{
420 			gl.deleteBuffers(1, &m_vbo);
421 		}
422 	}
423 
iterate()424 	IterateResult iterate() override
425 	{
426 
427 		tcu::TestLog&		  log = m_testCtx.getLog();
428 		const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
429 		ClipControlApi		  cc(m_context);
430 
431 		//Render a triangle fan covering(-1.0, -1.0) to(1.0, 0.0) and
432 		//write a pixel value of green(0, 1, 0).
433 
434 		de::SharedPtr<glu::ShaderProgram> program(
435 					new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
436 
437 		log << (*program);
438 		if (!program->isOk())
439 		{
440 			TCU_FAIL("Program compilation failed");
441 		}
442 
443 		gl.genVertexArrays(1, &m_vao);
444 		gl.bindVertexArray(m_vao);
445 
446 		gl.genBuffers(1, &m_vbo);
447 
448 		const float vertex_data0[] = { -1.0, -1.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0 };
449 
450 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
451 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
452 
453 		gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
454 		gl.enableVertexAttribArray(0);
455 
456 		gl.useProgram(program->getProgram());
457 
458 		glw::GLenum origins[] = { GL_UPPER_LEFT, GL_LOWER_LEFT };
459 
460 		qpTestResult result = QP_TEST_RESULT_PASS;
461 
462 		for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++)
463 		{
464 			//Clear the default framebuffer to red(1, 0, 0).
465 			gl.clearColor(1.0, 0.0, 0.0, 1.0);
466 			gl.clear(GL_COLOR_BUFFER_BIT);
467 
468 			//Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
469 			cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE);
470 			GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
471 
472 			//test method modification: use GL_TRIANGLE_STRIP, not FAN.
473 			gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
474 
475 			//Read back the default framebuffer with ReadPixels
476 			//Verify the green pixels at the top and red at the bottom.
477 			qpTestResult loopResult = ValidateFramebuffer(m_context, origins[orig]);
478 			if (loopResult != QP_TEST_RESULT_PASS)
479 			{
480 				result = loopResult;
481 			}
482 		}
483 
484 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
485 
486 		return STOP;
487 	}
488 
vsh()489 	const char* vsh()
490 	{
491 		return "attribute highp vec2 Position;"
492 			   "\n"
493 			   "void main() {"
494 			   "\n"
495 			   "    gl_Position = vec4(Position, 0.0, 1.0);"
496 			   "\n"
497 			   "}";
498 	}
499 
ValidateFramebuffer(Context & context,glw::GLenum origin)500 	qpTestResult ValidateFramebuffer(Context& context, glw::GLenum origin)
501 	{
502 		const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget();
503 		glw::GLsizei			 viewportW	= renderTarget.getWidth();
504 		glw::GLsizei			 viewportH	= renderTarget.getHeight();
505 		tcu::Surface			 renderedFrame(viewportW, viewportH);
506 		tcu::Surface			 referenceFrame(viewportW, viewportH);
507 
508 		tcu::TestLog& log = context.getTestContext().getLog();
509 
510 		for (int y = 0; y < renderedFrame.getHeight(); y++)
511 		{
512 			float yCoord = (float)(y) / (float)renderedFrame.getHeight();
513 
514 			for (int x = 0; x < renderedFrame.getWidth(); x++)
515 			{
516 
517 				float xCoord = (float)(x) / (float)renderedFrame.getWidth();
518 
519 				bool greenQuadrant;
520 
521 				if (origin == GL_UPPER_LEFT)
522 				{
523 					greenQuadrant = (yCoord > 0.5 && xCoord <= 0.5);
524 				}
525 				else
526 				{
527 					greenQuadrant = (yCoord <= 0.5 && xCoord <= 0.5);
528 				}
529 
530 				if (greenQuadrant)
531 				{
532 					referenceFrame.setPixel(x, y, tcu::RGBA::green());
533 				}
534 				else
535 				{
536 					referenceFrame.setPixel(x, y, tcu::RGBA::red());
537 				}
538 			}
539 		}
540 
541 		glu::readPixels(context.getRenderContext(), 0, 0, renderedFrame.getAccess());
542 
543 		if (tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
544 							  tcu::COMPARE_LOG_RESULT))
545 		{
546 			return QP_TEST_RESULT_PASS;
547 		}
548 		else
549 		{
550 			return QP_TEST_RESULT_FAIL;
551 		}
552 	}
553 
554 	glw::GLuint m_vao, m_vbo;
555 };
556 
557 
558 
559 /*
560  Clip Control Origin With Face Culling Test
561 
562  * Face culling should be tested with both <origin> settings.
563  The reason for that is, when doing Y-inversion, implementation
564  should not flip the calculated area sign for the triangle.
565  In other words, culling of CCW and CW triangles should
566  be orthogonal to used <origin> mode. Both triangle windings
567  and both <origin> modes should be tested. Here is the basic
568  outline of the test:
569 
570  - Clear the framebuffer to red (1,0,0).
571  - Enable GL_CULL_FACE, leave default front face & cull face (CCW, BACK)
572  - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
573  - Render a counter-clockwise triangles covering
574  (-1.0, -1.0) to (0.0, 1.0) and write a pixel value of green (0,1,0).
575  - Render a clockwise triangles covering
576  (0.0, -1.0) to (1.0, 1.0) and write a pixel value of green (0,1,0).
577  - Read back the framebuffer with ReadPixels
578  - Verify the green pixels at the left and red at the right.
579 
580  Repeat above test for ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE)
581  */
582 class ClipControlFaceCulling : public ClipControlRenderBaseTest
583 {
584 public:
ClipControlFaceCulling(Context & context,const char * name)585 	ClipControlFaceCulling(Context& context, const char* name)
586 		: ClipControlRenderBaseTest(context,  name, "Face culling test, both origins"), m_vao(0), m_vbo(0)
587 	{
588 	}
589 
deinit()590 	void deinit()
591 	{
592 		ClipControlRenderBaseTest::deinit();
593 
594 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
595 
596 		if (ClipControlApi::Supported(m_context))
597 		{
598 			ClipControlApi cc(m_context);
599 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
600 		}
601 
602 		gl.disable(GL_CULL_FACE);
603 
604 		gl.clearColor(0.0, 0.0, 0.0, 0.0);
605 
606 		gl.disable(GL_DEPTH_TEST);
607 		gl.depthFunc(GL_LESS);
608 
609 		if (m_vao)
610 		{
611 			gl.deleteVertexArrays(1, &m_vao);
612 		}
613 		if (m_vbo)
614 		{
615 			gl.deleteBuffers(1, &m_vbo);
616 		}
617 	}
618 
iterate()619 	IterateResult iterate()
620 	{
621 
622 		tcu::TestLog&		  log = m_testCtx.getLog();
623 		const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
624 		ClipControlApi		  cc(m_context);
625 
626 		//Enable GL_CULL_FACE, leave default front face & cull face(CCW, BACK)
627 		gl.enable(GL_CULL_FACE);
628 
629 		//Render a counter-clockwise triangles covering
630 		//(-1.0, -1.0) to(0.0, 1.0) and write a pixel value of green(0, 1, 0).
631 		//Render a clockwise triangles covering
632 		//(0.0, -1.0) to(1.0, 1.0) and write a pixel value of green(0, 1, 0).
633 		de::SharedPtr<glu::ShaderProgram> program(
634 					new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
635 
636 		log << (*program);
637 		if (!program->isOk())
638 		{
639 			TCU_FAIL("Program compilation failed");
640 		}
641 
642 		gl.genVertexArrays(1, &m_vao);
643 		gl.bindVertexArray(m_vao);
644 
645 		gl.genBuffers(1, &m_vbo);
646 
647 		const float vertex_data0[] = {
648 			//CCW
649 			-1.0, -1.0, 0.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, -1.0, 1.0,
650 			//CW
651 			0.0, -1.0, 0.0, 1.0, 1.0, -1.0, 1.0, -1.0, 0.0, 1.0, 1.0, 1.0,
652 		};
653 
654 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
655 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
656 
657 		gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
658 		gl.enableVertexAttribArray(0);
659 
660 		gl.useProgram(program->getProgram());
661 
662 		glw::GLenum origins[] = { GL_UPPER_LEFT, GL_LOWER_LEFT };
663 
664 		qpTestResult result = QP_TEST_RESULT_PASS;
665 
666 		for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++)
667 		{
668 			//Clear the framebuffer to red (1,0,0).
669 			gl.clearColor(1.0, 0.0, 0.0, 1.0);
670 			gl.clear(GL_COLOR_BUFFER_BIT);
671 
672 			gl.drawArrays(GL_TRIANGLES, 0, 12);
673 
674 			//Set ClipControl(<origin>, NEGATIVE_ONE_TO_ONE)
675 			cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE);
676 			GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
677 
678 			//Read back the framebuffer with ReadPixels
679 			//Verify the green pixels at the left and red at the right.
680 			qpTestResult loopResult = ValidateFramebuffer(m_context);
681 			if (loopResult != QP_TEST_RESULT_PASS)
682 			{
683 				result = loopResult;
684 			}
685 		}
686 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
687 
688 		return STOP;
689 	}
690 
vsh()691 	const char* vsh()
692 	{
693 		return "attribute  highp vec3 Position;"
694 			   "\n"
695 			   "void main() {"
696 			   "\n"
697 			   "    gl_Position = vec4(Position, 1.0);"
698 			   "\n"
699 			   "}";
700 	}
701 
ValidateFramebuffer(Context & context)702 	qpTestResult ValidateFramebuffer(Context& context)
703 	{
704 		const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget();
705 		glw::GLsizei			 viewportW	= renderTarget.getWidth();
706 		glw::GLsizei			 viewportH	= renderTarget.getHeight();
707 		tcu::Surface			 renderedColorFrame(viewportW, viewportH);
708 		tcu::Surface			 referenceColorFrame(viewportW, viewportH);
709 		tcu::TestLog&			 log = context.getTestContext().getLog();
710 
711 		for (int y = 0; y < renderedColorFrame.getHeight(); y++)
712 		{
713 			for (int x = 0; x < renderedColorFrame.getWidth(); x++)
714 			{
715 				float xCoord = (float)(x) / (float)renderedColorFrame.getWidth();
716 
717 				if (xCoord < 0.5f)
718 				{
719 					referenceColorFrame.setPixel(x, y, tcu::RGBA::green());
720 				}
721 				else
722 				{
723 					referenceColorFrame.setPixel(x, y, tcu::RGBA::red());
724 				}
725 			}
726 		}
727 
728 		glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess());
729 		if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame,
730 							   0.05f, tcu::COMPARE_LOG_RESULT))
731 		{
732 
733 			return QP_TEST_RESULT_FAIL;
734 		}
735 		return QP_TEST_RESULT_PASS;
736 	}
737 
738 	glw::GLuint m_vao, m_vbo;
739 };
740 
741 /*
742  Viewport Bounds Test
743 
744  * Viewport bounds should be tested, to ensure that rendering with flipped
745  origin affects only viewport area.
746 
747  This can be done by clearing the window to blue, making viewport
748  a non-symmetric-in-any-way subset of the window, than rendering
749  full-viewport multiple color quad. The (-1.0, -1.0)..(0.0, 0.0) quadrant
750  of a quad is red, the rest is green.
751  Whatever the origin is, the area outside of the viewport should stay blue.
752  If origin is LOWER_LEFT the "lower left" portion of the viewport is red,
753  if origin is UPPER_LEFT the "top left" portion of the viewport is red
754  (and in both cases the rest of viewport is green).
755 
756  Here is the basic outline of the test:
757 
758  - Clear the default framebuffer to blue (0,0,1).
759  - Set viewport to A = (x, y, w, h) = (1/8, 1/4, 1/2, 1/4)  in terms of proportional window size
760  - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
761  - Render a triangle strip covering (-1.0, -1.0) to (1.0, 1.0).
762  Write a pixel value of red (0,1,0) to (-1.0, -1.0)..(0.0, 0.0), other parts are green
763  - Reset viewport to defaults
764  - Read back the default framebuffer with ReadPixels
765  - Verify:
766  - regions outside A viewport are green
767  - Inside A viewport upper upper left portion is red, rest is green.
768 
769  Repeat the above test with LOWER_LEFT origin and lower left portion of A is red,
770  rest is green.
771  */
772 class ClipControlViewportBounds : public ClipControlRenderBaseTest
773 {
774 public:
ClipControlViewportBounds(Context & context,const char * name)775 	ClipControlViewportBounds(Context& context, const char* name)
776 		: ClipControlRenderBaseTest(context,  name, "Clip Control Origin Test"), m_vao(0), m_vbo(0)
777 	{
778 	}
779 
deinit()780 	void deinit() override
781 	{
782 		ClipControlRenderBaseTest::deinit();
783 
784 		const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
785 		glw::GLsizei				 windowW	  = renderTarget.getWidth();
786 		glw::GLsizei				 windowH	  = renderTarget.getHeight();
787 		const glw::Functions&	gl			  = m_context.getRenderContext().getFunctions();
788 
789 		if (ClipControlApi::Supported(m_context))
790 		{
791 			ClipControlApi cc(m_context);
792 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
793 		}
794 
795 		gl.clearColor(0.0, 0.0, 0.0, 0.0);
796 		gl.viewport(0, 0, windowW, windowH);
797 
798 		if (m_vao)
799 		{
800 			gl.deleteVertexArrays(1, &m_vao);
801 		}
802 		if (m_vbo)
803 		{
804 			gl.deleteBuffers(1, &m_vbo);
805 		}
806 	}
807 
iterate()808 	IterateResult iterate() override
809 	{
810 		tcu::TestLog&			 log		  = m_testCtx.getLog();
811 		const glw::Functions&	gl			  = m_context.getRenderContext().getFunctions();
812 		const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
813 		glw::GLsizei			 windowW	  = renderTarget.getWidth();
814 		glw::GLsizei			 windowH	  = renderTarget.getHeight();
815 		ClipControlApi			 cc(m_context);
816 
817 		//Clear the default framebuffer to blue (0,0,1).
818 		gl.clearColor(0.0, 0.0, 1.0, 1.0);
819 		gl.clear(GL_COLOR_BUFFER_BIT);
820 
821 		de::SharedPtr<glu::ShaderProgram> program(
822 					new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
823 
824 		log << (*program);
825 		if (!program->isOk())
826 		{
827 			TCU_FAIL("Program compilation failed");
828 		}
829 		gl.genVertexArrays(1, &m_vao);
830 		gl.bindVertexArray(m_vao);
831 
832 		gl.genBuffers(1, &m_vbo);
833 
834 		const float vertex_data0[] = { -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0 };
835 
836 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
837 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
838 
839 		gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
840 		gl.enableVertexAttribArray(0);
841 
842 		gl.useProgram(program->getProgram());
843 
844 		glw::GLenum origins[] = { GL_UPPER_LEFT, GL_LOWER_LEFT };
845 
846 		qpTestResult result = QP_TEST_RESULT_PASS;
847 
848 		for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++)
849 		{
850 			//Set viewport to A = (x, y, w, h) = (1/8, 1/4, 1/2, 1/4) in terms of proportional window size
851 			gl.viewport(static_cast<glw::GLint>((0.125f * static_cast<float>(windowW))+0.5f),
852 						static_cast<glw::GLint>((0.25f * static_cast<float>(windowH))+0.5f),
853 						static_cast<glw::GLsizei>((0.5f * static_cast<float>(windowW))+0.5f),
854 						static_cast<glw::GLsizei>((0.25f * static_cast<float>(windowH))+0.5f));
855 
856 			//Set ClipControl(<origin>, NEGATIVE_ONE_TO_ONE)
857 			cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE);
858 			GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
859 
860 			//Render a triangle strip covering (-1.0, -1.0) to (1.0, 1.0).
861 			//Write a pixel value of red (0,1,0) to (-1.0, -1.0)..(0.0, 0.0), other parts are green
862 			gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
863 
864 			gl.viewport(0, 0, windowW, windowH);
865 
866 			//Read back the default framebuffer with ReadPixels
867 			//Verify the green pixels at the top and red at the bottom.
868 			qpTestResult loopResult = ValidateFramebuffer(m_context, origins[orig]);
869 			if (loopResult != QP_TEST_RESULT_PASS)
870 			{
871 				result = loopResult;
872 			}
873 		}
874 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
875 		return STOP;
876 	}
877 
vsh()878 	const char* vsh()
879 	{
880 		return "attribute highp vec2 Position;"
881 			   "\n"
882 			   "varying highp vec2 PositionOut;"
883 			   "\n"
884 			   "void main() {"
885 			   "\n"
886 			   "    gl_Position = vec4(Position, 0.0, 1.0);"
887 			   "\n"
888 			   "    PositionOut = Position;"
889 			   "\n"
890 			   "}";
891 	}
892 
fsh()893 	const char* fsh()
894 	{
895 		return "varying highp vec2 PositionOut;"
896 			   "\n"
897 			   "void main() {"
898 			   "\n"
899 			   "    if (PositionOut.x < 0.0 && PositionOut.y < 0.0)"
900 			   "\n"
901 			   "       gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);"
902 			   "\n"
903 			   "    else"
904 			   "\n"
905 			   "       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);"
906 			   "\n"
907 			   "}";
908 	}
909 
ValidateFramebuffer(Context & context,glw::GLenum origin)910 	qpTestResult ValidateFramebuffer(Context& context, glw::GLenum origin)
911 	{
912 		const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget();
913 		glw::GLsizei				 windowW	  = renderTarget.getWidth();
914 		glw::GLsizei				 windowH	  = renderTarget.getHeight();
915 		tcu::Surface			 renderedFrame(windowW, windowH);
916 		tcu::Surface			 referenceFrame(windowW, windowH);
917 
918 		tcu::TestLog& log = context.getTestContext().getLog();
919 
920 		for (int y = 0; y < renderedFrame.getHeight(); y++)
921 		{
922 			float yCoord   = static_cast<float>(y) / static_cast<float>(renderedFrame.getHeight());
923 			float yVPCoord = (yCoord - 0.25f) * 4.0f;
924 
925 			for (int x = 0; x < renderedFrame.getWidth(); x++)
926 			{
927 				float xCoord   = static_cast<float>(x) / static_cast<float>(renderedFrame.getWidth());
928 				float xVPCoord = (xCoord - 0.125f) * 2.0f;
929 
930 				if (xVPCoord > 0.0f && xVPCoord < 1.0f && yVPCoord > 0.0f && yVPCoord < 1.0f)
931 				{
932 
933 					bool greenQuadrant;
934 
935 					//inside viewport
936 					if (origin == GL_UPPER_LEFT)
937 					{
938 						greenQuadrant = (yVPCoord > 0.5f && xVPCoord <= 0.5f);
939 					}
940 					else
941 					{
942 						greenQuadrant = (yVPCoord <= 0.5f && xVPCoord <= 0.5f);
943 					}
944 
945 					if (greenQuadrant)
946 					{
947 						referenceFrame.setPixel(x, y, tcu::RGBA::green());
948 					}
949 					else
950 					{
951 						referenceFrame.setPixel(x, y, tcu::RGBA::red());
952 					}
953 				}
954 				else
955 				{
956 					//outside viewport
957 					referenceFrame.setPixel(x, y, tcu::RGBA::blue());
958 				}
959 			}
960 		}
961 
962 		glu::readPixels(context.getRenderContext(), 0, 0, renderedFrame.getAccess());
963 
964 		if (tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
965 							  tcu::COMPARE_LOG_RESULT))
966 		{
967 			return QP_TEST_RESULT_PASS;
968 		}
969 		else
970 		{
971 			return QP_TEST_RESULT_FAIL;
972 		}
973 	}
974 
975 	glw::GLuint m_vao, m_vbo;
976 };
977 
978 /*   Depth Mode Test
979 
980  * Basic <depth> behavior can be tested by writing specific z_c (z
981  clip coordinates) and observing its clipping and transformation.
982  Create and bind a framebuffer object with a floating-point depth
983  buffer attachment. Make sure depth clamping is disabled. The best
984  steps for verifying the correct depth mode:
985 
986  - Clear the depth buffer to 0.5.
987  - Set ClipControl(LOWER_LEFT, ZERO_TO_ONE)
988  - Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
989  - Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
990  - Read back the floating-point depth buffer with ReadPixels
991  - Verify that the pixels with a Z clip coordinate less than 0.0 are
992  clipped and those coordinates from 0.0 to 1.0 update the depth
993  buffer with values 0.0 to 1.0.
994  */
995 
996 class ClipControlDepthModeTest : public ClipControlRenderBaseTest
997 {
998 public:
ClipControlDepthModeTest(Context & context,const char * name,const char * subname)999 	ClipControlDepthModeTest(Context& context, const char* name, const char* subname)
1000 		: ClipControlRenderBaseTest(context, name, subname)
1001 	{
1002 
1003 	}
1004 
init()1005 	void init() override
1006 	{
1007 		const glw::Functions&	gl			  = m_context.getRenderContext().getFunctions();
1008 		const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
1009 		glw::GLuint				 viewportW	= renderTarget.getWidth();
1010 		glw::GLuint				 viewportH	= renderTarget.getHeight();
1011 
1012 		ClipControlRenderBaseTest::init();
1013 
1014 		gl.genFramebuffers(1, &m_fboD);
1015 
1016 		gl.genTextures(1, &m_texDepthResolve);
1017 		gl.bindTexture(GL_TEXTURE_2D, m_texDepthResolve);
1018 		setupTexture();
1019 		gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewportW, viewportH, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
1020 	}
1021 
deinit()1022 	void deinit() override
1023 	{
1024 		const glw::Functions&	gl			  = m_context.getRenderContext().getFunctions();
1025 
1026 		gl.deleteTextures(1, &m_texDepthResolve);
1027 		gl.deleteFramebuffers(1, &m_fboD);
1028 
1029 		ClipControlRenderBaseTest::deinit();
1030 	}
1031 
setupTexture()1032 	void setupTexture()
1033 	{
1034 		const glw::Functions&	gl			  = m_context.getRenderContext().getFunctions();
1035 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1036 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1037 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1038 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1039 	}
1040 
readDepthPixels(const tcu::PixelBufferAccess & pixelBuf)1041 	void readDepthPixels(const tcu::PixelBufferAccess& pixelBuf)
1042 	{
1043 
1044 		const char* vs = "\n"
1045 						 "attribute vec4 pos;\n"
1046 						 "attribute vec2 UV;\n"
1047 						 "varying highp vec2 vUV;\n"
1048 						 "void main() {\n"
1049 						 "  gl_Position = pos;\n"
1050 						 "  vUV = UV;\n"
1051 						 "}\n";
1052 
1053 		const char* fs = "\n"
1054 						 "precision mediump float;\n"
1055 						 "varying vec2 vUV;\n"
1056 						 "uniform sampler2D tex;\n"
1057 						 "void main() {\n"
1058 						 "  gl_FragColor = texture2D(tex, vUV).rrrr;\n"
1059 						 "}\n";
1060 
1061 		const glu::RenderContext&	renderContext	= m_context.getRenderContext();
1062 		const glw::Functions&		gl				= renderContext.getFunctions();
1063 		const tcu::RenderTarget&	renderTarget	= renderContext.getRenderTarget();
1064 		glw::GLsizei				windowW			= renderTarget.getWidth();
1065 		glw::GLsizei				windowH			= renderTarget.getHeight();
1066 
1067 		glu::ShaderProgram program(renderContext,  glu::makeVtxFragSources(vs, fs));
1068 
1069 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboD);
1070 		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texDepthResolve, 0);
1071 
1072 		gl.disable(GL_DEPTH_TEST);
1073 		gl.depthMask(GL_FALSE);
1074 		gl.disable(GL_STENCIL_TEST);
1075 		gl.viewport(0, 0, windowW, windowH);
1076 		gl.clearColor(0.0f, 0.2f, 1.0f, 1.0f);
1077 		gl.clear(GL_COLOR_BUFFER_BIT);
1078 
1079 		const int	texLoc	= gl.getUniformLocation(program.getProgram(), "tex");
1080 
1081 		gl.bindVertexArray(0);
1082 		gl.bindBuffer(GL_ARRAY_BUFFER, 0);
1083 
1084 		gl.bindTexture(GL_TEXTURE_2D, getDepthTexture());
1085 		setupTexture();
1086 
1087 		gl.useProgram(program.getProgram());
1088 		gl.uniform1i(texLoc, 0);
1089 
1090 		{
1091 			const GLfloat vertices[] = {
1092 				-1.0f, -1.0f, 0.0f, 1.0f,
1093 				1.0f, -1.0f, 0.0f, 1.0f,
1094 				-1.0f,  1.0f, 0.0f, 1.0f,
1095 				1.0f,  1.0f, 0.0f, 1.0f,
1096 			};
1097 			const GLfloat texCoords[] = {
1098 				0.0f, 0.0f,
1099 				1.0f, 0.0f,
1100 				0.0f, 1.0f,
1101 				1.0f, 1.0f,
1102 			};
1103 			const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1104 
1105 			const glu::VertexArrayBinding	vertexArray[]	= { glu::va::Float("pos", 4, 4, 0, vertices),
1106 																glu::va::Float("UV", 2, 4, 0, texCoords) };
1107 
1108 			glu::draw(renderContext, program.getProgram(), 2, vertexArray,
1109 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), indices));
1110 		}
1111 		glu::readPixels(renderContext, 0, 0, pixelBuf);
1112 	}
1113 
1114 	GLuint m_fboD;
1115 	GLuint m_texDepthResolve;
1116 
1117 };
1118 
1119 class ClipControlDepthModeZeroToOneTest : public ClipControlDepthModeTest
1120 {
1121 public:
ClipControlDepthModeZeroToOneTest(Context & context,const char * name)1122 	ClipControlDepthModeZeroToOneTest(Context& context, const char* name)
1123 		: ClipControlDepthModeTest(context, name, "Depth Mode Test, ZERO_TO_ONE"), m_vao(0), m_vbo(0)
1124 	{
1125 
1126 	}
1127 
deinit()1128 	void deinit() override
1129 	{
1130 		ClipControlDepthModeTest::deinit();
1131 
1132 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1133 
1134 		if (ClipControlApi::Supported(m_context))
1135 		{
1136 			ClipControlApi cc(m_context);
1137 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
1138 		}
1139 
1140 		gl.clearDepthf(0.0f);
1141 		gl.clearColor(0.0, 0.0, 0.0, 0.0);
1142 
1143 		gl.disable(GL_DEPTH_TEST);
1144 		gl.depthFunc(GL_LESS);
1145 
1146 		if (m_vao)
1147 		{
1148 			gl.deleteVertexArrays(1, &m_vao);
1149 		}
1150 		if (m_vbo)
1151 		{
1152 			gl.deleteBuffers(1, &m_vbo);
1153 		}
1154 	}
1155 
iterate()1156 	IterateResult iterate() override
1157 	{
1158 
1159 		tcu::TestLog&		  log = m_testCtx.getLog();
1160 		const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
1161 		ClipControlApi		  cc(m_context);
1162 
1163 		gl.clearColor(1.0, 0.0, 0.0, 1.0);
1164 		gl.clear(GL_COLOR_BUFFER_BIT);
1165 
1166 		//Clear the depth buffer to 0.5.
1167 		gl.clearDepthf(0.5);
1168 		gl.clear(GL_DEPTH_BUFFER_BIT);
1169 
1170 		//Set ClipControl(LOWER_LEFT, ZERO_TO_ONE)
1171 		cc.clipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
1172 		GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
1173 
1174 		//Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1175 		gl.enable(GL_DEPTH_TEST);
1176 		gl.depthFunc(GL_ALWAYS);
1177 
1178 		//Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1179 		de::SharedPtr<glu::ShaderProgram> program(
1180 					new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
1181 
1182 		log << (*program);
1183 		if (!program->isOk())
1184 		{
1185 			TCU_FAIL("Program compilation failed");
1186 		}
1187 
1188 		gl.genVertexArrays(1, &m_vao);
1189 		gl.bindVertexArray(m_vao);
1190 
1191 		gl.genBuffers(1, &m_vbo);
1192 
1193 		const float vertex_data0[] = {
1194 			-1.0, -1.0, -1.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0,
1195 		};
1196 
1197 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
1198 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
1199 
1200 		gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
1201 		gl.enableVertexAttribArray(0);
1202 
1203 		gl.useProgram(program->getProgram());
1204 
1205 		//test method modification: use GL_TRIANGLE_STRIP, not FAN.
1206 		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1207 
1208 		//Read back the floating-point depth buffer with ReadPixels
1209 		//Verify that the pixels with a Z clip coordinate less than 0.0 are
1210 		//  clipped and those coordinates from 0.0 to 1.0 update the depth
1211 		//  buffer with values 0.0 to 1.0.
1212 		qpTestResult result = ValidateFramebuffer(m_context);
1213 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
1214 
1215 		return STOP;
1216 	}
1217 
vsh()1218 	const char* vsh()
1219 	{
1220 		return "attribute vec3 Position;"
1221 			   "\n"
1222 			   "void main() {"
1223 			   "\n"
1224 			   "    gl_Position = vec4(Position, 1.0);"
1225 			   "\n"
1226 			   "}";
1227 	}
1228 
ValidateFramebuffer(Context & context)1229 	qpTestResult ValidateFramebuffer(Context& context)
1230 	{
1231 		const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget();
1232 		glw::GLuint				 viewportW	= renderTarget.getWidth();
1233 		glw::GLuint				 viewportH	= renderTarget.getHeight();
1234 		tcu::Surface			 renderedColorFrame(viewportW, viewportH);
1235 		tcu::Surface			 referenceColorFrame(viewportW, viewportH);
1236 		tcu::TextureFormat		 depthReadbackFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1237 		tcu::TextureFormat		 depthFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
1238 		tcu::TextureLevel		 renderedDepthFrame(depthReadbackFormat, viewportW, viewportH);
1239 		tcu::TextureLevel		 referenceDepthFrame(depthFormat, viewportW, viewportH);
1240 		tcu::TextureLevel		 importanceMaskFrame(depthFormat, viewportW, viewportH);
1241 
1242 		tcu::TestLog& log = context.getTestContext().getLog();
1243 
1244 		const float rasterizationError =
1245 				2.0f / (float)renderedColorFrame.getHeight() + 2.0f / (float)renderedColorFrame.getWidth();
1246 
1247 		for (int y = 0; y < renderedColorFrame.getHeight(); y++)
1248 		{
1249 			float yCoord = ((float)(y) + 0.5f) / (float)renderedColorFrame.getHeight();
1250 
1251 			for (int x = 0; x < renderedColorFrame.getWidth(); x++)
1252 			{
1253 				float xCoord = ((float)(x) + 0.5f) / (float)renderedColorFrame.getWidth();
1254 
1255 				if (yCoord >= 1.0 - xCoord - rasterizationError && yCoord <= 1.0 - xCoord + rasterizationError)
1256 				{
1257 					importanceMaskFrame.getAccess().setPixDepth(0.0f, x, y);
1258 				}
1259 				else
1260 				{
1261 					importanceMaskFrame.getAccess().setPixDepth(1.0f, x, y);
1262 				}
1263 
1264 				if (yCoord < 1.0 - xCoord)
1265 				{
1266 					referenceColorFrame.setPixel(x, y, tcu::RGBA::red());
1267 					referenceDepthFrame.getAccess().setPixDepth(0.5f, x, y);
1268 				}
1269 				else
1270 				{
1271 					referenceColorFrame.setPixel(x, y, tcu::RGBA::green());
1272 
1273 					referenceDepthFrame.getAccess().setPixDepth(-1.0f + xCoord + yCoord, x, y);
1274 				}
1275 			}
1276 		}
1277 
1278 		glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess());
1279 		if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame,
1280 							   0.05f, tcu::COMPARE_LOG_RESULT))
1281 		{
1282 
1283 			return QP_TEST_RESULT_FAIL;
1284 		}
1285 
1286 		readDepthPixels(renderedDepthFrame.getAccess());
1287 		if (!fuzzyDepthCompare(log, "Result", "Depth image comparison result", referenceDepthFrame, renderedDepthFrame,
1288 							   0.05f, &importanceMaskFrame))
1289 		{
1290 			return QP_TEST_RESULT_FAIL;
1291 		}
1292 		return QP_TEST_RESULT_PASS;
1293 	}
1294 
1295 	glw::GLuint m_vao, m_vbo;
1296 };
1297 
1298 /*
1299  Do the same as above, but use the default NEGATIVE_ONE_TO_ONE depth mode:
1300 
1301  - Clear the depth buffer to 0.5.
1302  - Set ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE)
1303  - Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1304  - Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1305  - Read back the floating-point depth buffer with ReadPixels
1306  - Verify that no pixels are clipped and the depth buffer contains
1307  values from 0.0 to 1.0.
1308  */
1309 class ClipControlDepthModeOneToOneTest : public ClipControlDepthModeTest
1310 {
1311 public:
ClipControlDepthModeOneToOneTest(Context & context,const char * name)1312 	ClipControlDepthModeOneToOneTest(Context& context, const char* name)
1313 		: ClipControlDepthModeTest(context, name, "Depth Mode Test, ONE_TO_ONE"), m_vao(0), m_vbo(0)
1314 	{
1315 	}
1316 
deinit()1317 	void deinit() override
1318 	{
1319 		ClipControlDepthModeTest::deinit();
1320 
1321 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1322 
1323 		if (ClipControlApi::Supported(m_context))
1324 		{
1325 			ClipControlApi cc(m_context);
1326 			cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
1327 		}
1328 
1329 		gl.clearDepthf(0.0);
1330 		gl.clearColor(0.0, 0.0, 0.0, 0.0);
1331 
1332 		gl.disable(GL_DEPTH_TEST);
1333 		gl.depthFunc(GL_LESS);
1334 
1335 		if (m_vao)
1336 		{
1337 			gl.deleteVertexArrays(1, &m_vao);
1338 		}
1339 		if (m_vbo)
1340 		{
1341 			gl.deleteBuffers(1, &m_vbo);
1342 		}
1343 	}
1344 
iterate()1345 	IterateResult iterate() override
1346 	{
1347 		tcu::TestLog&		  log = m_testCtx.getLog();
1348 		const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
1349 		ClipControlApi		  cc(m_context);
1350 
1351 		gl.clearColor(1.0, 0.0, 0.0, 1.0);
1352 		gl.clear(GL_COLOR_BUFFER_BIT);
1353 
1354 		//Clear the depth buffer to 0.5.
1355 		gl.clearDepthf(0.5f);
1356 		gl.clear(GL_DEPTH_BUFFER_BIT);
1357 
1358 		//Set ClipControl(LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE)
1359 		cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
1360 		GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
1361 
1362 		//Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1363 		gl.enable(GL_DEPTH_TEST);
1364 		gl.depthFunc(GL_ALWAYS);
1365 
1366 		//Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1367 		de::SharedPtr<glu::ShaderProgram> program(
1368 					new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
1369 
1370 		log << (*program);
1371 		if (!program->isOk())
1372 		{
1373 			TCU_FAIL("Program compilation failed");
1374 		}
1375 
1376 		gl.genVertexArrays(1, &m_vao);
1377 		gl.bindVertexArray(m_vao);
1378 
1379 		gl.genBuffers(1, &m_vbo);
1380 
1381 		const float vertex_data0[] = {
1382 			-1.0, -1.0, -1.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0,
1383 		};
1384 
1385 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
1386 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
1387 
1388 		gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
1389 		gl.enableVertexAttribArray(0);
1390 
1391 		gl.useProgram(program->getProgram());
1392 
1393 		//test method modification: use GL_TRIANGLE_STRIP, not FAN.
1394 		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1395 
1396 		//Read back the floating-point depth buffer with ReadPixels
1397 		//Verify that the pixels with a Z clip coordinate less than 0.0 are
1398 		//  clipped and those coordinates from 0.0 to 1.0 update the depth
1399 		//  buffer with values 0.0 to 1.0.
1400 		qpTestResult result = ValidateFramebuffer(m_context);
1401 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
1402 
1403 		return STOP;
1404 	}
1405 
vsh()1406 	const char* vsh()
1407 	{
1408 		return "attribute vec3 Position;"
1409 			   "\n"
1410 			   "void main() {"
1411 			   "\n"
1412 			   "    gl_Position = vec4(Position, 1.0);"
1413 			   "\n"
1414 			   "}";
1415 	}
1416 
ValidateFramebuffer(Context & context)1417 	qpTestResult ValidateFramebuffer(Context& context)
1418 	{
1419 		const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget();
1420 		glw::GLuint				 viewportW	= renderTarget.getWidth();
1421 		glw::GLuint				 viewportH	= renderTarget.getHeight();
1422 		tcu::Surface			 renderedColorFrame(viewportW, viewportH);
1423 		tcu::Surface			 referenceColorFrame(viewportW, viewportH);
1424 		tcu::TextureFormat		 depthReadbackFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1425 		tcu::TextureFormat		 depthFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
1426 		tcu::TextureLevel		 renderedDepthFrame(depthReadbackFormat, viewportW, viewportH);
1427 		tcu::TextureLevel		 referenceDepthFrame(depthFormat, viewportW, viewportH);
1428 
1429 		tcu::TestLog& log = context.getTestContext().getLog();
1430 
1431 		for (int y = 0; y < renderedColorFrame.getHeight(); y++)
1432 		{
1433 			float yCoord = (float)(y) / (float)renderedColorFrame.getHeight();
1434 			for (int x = 0; x < renderedColorFrame.getWidth(); x++)
1435 			{
1436 				float xCoord = (float)(x) / (float)renderedColorFrame.getWidth();
1437 
1438 				referenceColorFrame.setPixel(x, y, tcu::RGBA::green());
1439 				referenceDepthFrame.getAccess().setPixDepth((xCoord + yCoord) * 0.5f, x, y);
1440 			}
1441 		}
1442 
1443 		glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess());
1444 		if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame,
1445 							   0.05f, tcu::COMPARE_LOG_RESULT))
1446 		{
1447 			return QP_TEST_RESULT_FAIL;
1448 		}
1449 
1450 		readDepthPixels(renderedDepthFrame.getAccess());
1451 		if (!fuzzyDepthCompare(log, "Result", "Depth image comparison result", referenceDepthFrame, renderedDepthFrame,
1452 							   0.05f))
1453 		{
1454 			return QP_TEST_RESULT_FAIL;
1455 		}
1456 
1457 		return QP_TEST_RESULT_PASS;
1458 	}
1459 
1460 	glw::GLuint m_vao, m_vbo;
1461 };
1462 
1463 
1464 /** Constructor.
1465  *
1466  *  @param context Rendering context.
1467  **/
ClipControlTests(Context & context)1468 ClipControlTests::ClipControlTests(Context& context)
1469 	: TestCaseGroup(context, "clip_control", "Verifies \"clip_control\" functionality")
1470 {
1471 	/* Left blank on purpose */
1472 }
1473 
1474 /** Destructor.
1475  *
1476  **/
~ClipControlTests()1477 ClipControlTests::~ClipControlTests()
1478 {
1479 }
1480 
1481 /** Initializes a texture_storage_multisample test group.
1482  *
1483  **/
init(void)1484 void ClipControlTests::init(void)
1485 {
1486 	addChild(new ClipControlInitialState(m_context, "initial"));
1487 	addChild(new ClipControlModifyGetState(m_context, "modify_get"));
1488 	addChild(new ClipControlErrors(m_context, "errors"));
1489 	addChild(new ClipControlOriginTest(m_context, "origin"));
1490 	addChild(new ClipControlDepthModeZeroToOneTest(m_context, "depth_mode_zero_to_one"));
1491 	addChild(new ClipControlDepthModeOneToOneTest(m_context, "depth_mode_one_to_one"));
1492 	addChild(new ClipControlFaceCulling(m_context, "face_culling"));
1493 	addChild(new ClipControlViewportBounds(m_context, "viewport_bounds"));
1494 }
1495 }
1496 }
1497 }
1498 
1499