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
50namespace deqp
51{
52namespace gles2
53{
54namespace Functional
55{
56
57class ClipControlApi
58{
59public:
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
69	static bool Supported(Context& context)
70	{
71		return context.getContextInfo().isExtensionSupported("GL_EXT_clip_control");
72	}
73
74	glw::glClipControlFunc clipControl;
75
76private:
77	Context& m_context;
78};
79
80class ClipControlBaseTest : public TestCase
81{
82protected:
83	ClipControlBaseTest(Context& context, const char* name, const char* description)
84		: TestCase(context, name, description)
85	{
86	}
87
88	void init() override
89	{
90		ClipControlApi api(m_context);
91	}
92
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
114class ClipControlRenderBaseTest : public ClipControlBaseTest
115{
116protected:
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
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
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
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
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
203	GLuint getDepthTexture()
204	{
205		return m_depthTexure;
206	}
207
208private:
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 */
223class ClipControlInitialState : public ClipControlBaseTest
224{
225public:
226	ClipControlInitialState(Context& context, const char* name)
227		: ClipControlBaseTest(context, name, "Verify initial state")
228	{
229	}
230
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 */
256class ClipControlModifyGetState : public ClipControlBaseTest
257{
258public:
259	ClipControlModifyGetState(Context& context, const char* name)
260		: ClipControlBaseTest(context,  name, "Verify initial state")
261	{
262	}
263
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
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 */
314class ClipControlErrors : public ClipControlBaseTest
315{
316public:
317	ClipControlErrors(Context& context, const char* name)
318		: ClipControlBaseTest(context, name, "Verify that proper errors are generated when using ClipControl.")
319	{
320	}
321
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
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 */
394class ClipControlOriginTest : public ClipControlRenderBaseTest
395{
396public:
397	ClipControlOriginTest(Context& context, const char* name)
398		: ClipControlRenderBaseTest(context,  name, "Clip Control Origin Test"), m_vao(0), m_vbo(0)
399	{
400	}
401
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
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
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
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 */
582class ClipControlFaceCulling : public ClipControlRenderBaseTest
583{
584public:
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
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
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
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
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 */
772class ClipControlViewportBounds : public ClipControlRenderBaseTest
773{
774public:
775	ClipControlViewportBounds(Context& context, const char* name)
776		: ClipControlRenderBaseTest(context,  name, "Clip Control Origin Test"), m_vao(0), m_vbo(0)
777	{
778	}
779
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
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
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
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
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
996class ClipControlDepthModeTest : public ClipControlRenderBaseTest
997{
998public:
999	ClipControlDepthModeTest(Context& context, const char* name, const char* subname)
1000		: ClipControlRenderBaseTest(context, name, subname)
1001	{
1002
1003	}
1004
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
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
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
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
1119class ClipControlDepthModeZeroToOneTest : public ClipControlDepthModeTest
1120{
1121public:
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
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
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
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
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 */
1309class ClipControlDepthModeOneToOneTest : public ClipControlDepthModeTest
1310{
1311public:
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
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
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
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
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 **/
1468ClipControlTests::ClipControlTests(Context& context)
1469	: TestCaseGroup(context, "clip_control", "Verifies \"clip_control\" functionality")
1470{
1471	/* Left blank on purpose */
1472}
1473
1474/** Destructor.
1475 *
1476 **/
1477ClipControlTests::~ClipControlTests()
1478{
1479}
1480
1481/** Initializes a texture_storage_multisample test group.
1482 *
1483 **/
1484void 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