Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief glDepthRangef() tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fDepthRangeTests.hpp"
     25 #include "tcuVector.hpp"
     26 #include "tcuTestLog.hpp"
     27 #include "tcuSurface.hpp"
     28 #include "tcuImageCompare.hpp"
     29 #include "tcuRenderTarget.hpp"
     30 #include "gluPixelTransfer.hpp"
     31 #include "gluShaderProgram.hpp"
     32 #include "gluRenderContext.hpp"
     33 #include "deRandom.hpp"
     34 #include "deMath.h"
     35 #include "deString.h"
     36 
     37 #include "glw.h"
     38 
     39 namespace deqp
     40 {
     41 namespace gles2
     42 {
     43 namespace Functional
     44 {
     45 
     46 enum
     47 {
     48 	VISUALIZE_DEPTH_STEPS	= 32 //!< Number of depth steps in visualization
     49 };
     50 
     51 using tcu::Vec2;
     52 using tcu::Vec3;
     53 using tcu::Vec4;
     54 using tcu::TestLog;
     55 using std::string;
     56 using std::vector;
     57 
     58 static const char* s_vertexShaderSrc =
     59 	"attribute highp vec4 a_position;\n"
     60 	"attribute highp vec2 a_coord;\n"
     61 	"void main (void)\n"
     62 	"{\n"
     63 	"	gl_Position = a_position;\n"
     64 	"}\n";
     65 static const char* s_fragmentShaderSrc =
     66 	"uniform mediump vec4 u_color;\n"
     67 	"void main (void)\n"
     68 	"{\n"
     69 	"	gl_FragColor = u_color;\n"
     70 	"}\n";
     71 
     72 template <typename T>
     73 static inline bool compare (deUint32 func, T a, T b)
     74 {
     75 	switch (func)
     76 	{
     77 		case GL_NEVER:		return false;
     78 		case GL_ALWAYS:		return true;
     79 		case GL_LESS:		return a < b;
     80 		case GL_LEQUAL:		return a <= b;
     81 		case GL_EQUAL:		return a == b;
     82 		case GL_NOTEQUAL:	return a != b;
     83 		case GL_GEQUAL:		return a >= b;
     84 		case GL_GREATER:	return a > b;
     85 		default:
     86 			DE_ASSERT(DE_FALSE);
     87 			return false;
     88 	}
     89 }
     90 
     91 inline float triangleInterpolate (const float v0, const float v1, const float v2, const float x, const float y)
     92 {
     93 	return v0 + (v2-v0)*x + (v1-v0)*y;
     94 }
     95 
     96 inline float triQuadInterpolate (const float x, const float y, const tcu::Vec4& quad)
     97 {
     98 	// \note Top left fill rule.
     99 	if (x + y < 1.0f)
    100 		return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
    101 	else
    102 		return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
    103 }
    104 
    105 inline float depthRangeTransform (const float zd, const float zNear, const float zFar)
    106 {
    107 	const float	cNear	= de::clamp(zNear, 0.0f, 1.0f);
    108 	const float	cFar	= de::clamp(zFar, 0.0f, 1.0f);
    109 	return ((cFar - cNear)/2.0f) * zd + (cNear + cFar)/2.0f;
    110 }
    111 
    112 class DepthRangeCompareCase : public TestCase
    113 {
    114 public:
    115 							DepthRangeCompareCase	(Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc);
    116 							~DepthRangeCompareCase	(void);
    117 
    118 	IterateResult			iterate					(void);
    119 
    120 private:
    121 	const tcu::Vec4			m_depthCoord;
    122 	const float				m_zNear;
    123 	const float				m_zFar;
    124 	const deUint32			m_compareFunc;
    125 };
    126 
    127 DepthRangeCompareCase::DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc)
    128 	: TestCase			(context, name, desc)
    129 	, m_depthCoord		(depthCoord)
    130 	, m_zNear			(zNear)
    131 	, m_zFar			(zFar)
    132 	, m_compareFunc		(compareFunc)
    133 {
    134 }
    135 
    136 DepthRangeCompareCase::~DepthRangeCompareCase (void)
    137 {
    138 }
    139 
    140 DepthRangeCompareCase::IterateResult DepthRangeCompareCase::iterate (void)
    141 {
    142 	TestLog&					log					= m_testCtx.getLog();
    143 	de::Random					rnd					(deStringHash(getName()));
    144 	const tcu::RenderTarget&	renderTarget		= m_context.getRenderContext().getRenderTarget();
    145 	const int					viewportW			= de::min(128, renderTarget.getWidth());
    146 	const int					viewportH			= de::min(128, renderTarget.getHeight());
    147 	const int					viewportX			= rnd.getInt(0, renderTarget.getWidth()-viewportW);
    148 	const int					viewportY			= rnd.getInt(0, renderTarget.getHeight()-viewportH);
    149 	tcu::Surface				renderedFrame		(viewportW, viewportH);
    150 	tcu::Surface				referenceFrame		(viewportW, viewportH);
    151 	const float					constDepth			= 0.1f;
    152 
    153 	if (renderTarget.getDepthBits() == 0)
    154 		throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
    155 
    156 	const glu::ShaderProgram	program				(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));
    157 
    158 	if (!program.isOk())
    159 	{
    160 		log << program;
    161 		TCU_FAIL("Compile failed");
    162 	}
    163 
    164 	const int					colorLoc			= glGetUniformLocation(program.getProgram(), "u_color");
    165 	const int					posLoc				= glGetAttribLocation(program.getProgram(), "a_position");
    166 
    167 	m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage;
    168 
    169 	glViewport(viewportX, viewportY, viewportW, viewportH);
    170 	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    171 	glEnable(GL_DEPTH_TEST);
    172 	glUseProgram(program.getProgram());
    173 	glEnableVertexAttribArray(posLoc);
    174 
    175 	static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
    176 
    177 	// Fill viewport with 2 quads - one with constant depth and another with d = [-1..1]
    178 	{
    179 		static const float constDepthCoord[] =
    180 		{
    181 			-1.0f, -1.0f, constDepth, 1.0f,
    182 			-1.0f, +1.0f, constDepth, 1.0f,
    183 			 0.0f, -1.0f, constDepth, 1.0f,
    184 			 0.0f, +1.0f, constDepth, 1.0f
    185 		};
    186 		static const float varyingDepthCoord[] =
    187 		{
    188 			 0.0f, -1.0f, +1.0f, 1.0f,
    189 			 0.0f, +1.0f,  0.0f, 1.0f,
    190 			+1.0f, -1.0f,  0.0f, 1.0f,
    191 			+1.0f, +1.0f, -1.0f, 1.0f
    192 		};
    193 
    194 		glUniform4f(colorLoc, 0.0f, 0.0f, 1.0f, 1.0f);
    195 		glDepthFunc(GL_ALWAYS);
    196 
    197 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &constDepthCoord);
    198 		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
    199 
    200 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &varyingDepthCoord);
    201 		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
    202 
    203 		GLU_CHECK();
    204 	}
    205 
    206 	// Render with depth test.
    207 	{
    208 		const float position[] =
    209 		{
    210 			-1.0f, -1.0f, m_depthCoord[0], 1.0f,
    211 			-1.0f, +1.0f, m_depthCoord[1], 1.0f,
    212 			+1.0f, -1.0f, m_depthCoord[2], 1.0f,
    213 			+1.0f, +1.0f, m_depthCoord[3], 1.0f
    214 		};
    215 
    216 		glDepthRangef(m_zNear, m_zFar);
    217 		glDepthFunc(m_compareFunc);
    218 		glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
    219 
    220 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
    221 		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
    222 
    223 		GLU_CHECK();
    224 	}
    225 
    226 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
    227 
    228 	// Render reference.
    229 	for (int y = 0; y < referenceFrame.getHeight(); y++)
    230 	{
    231 		float	yf		= ((float)y + 0.5f) / (float)referenceFrame.getHeight();
    232 		int		half	= de::clamp((int)((float)referenceFrame.getWidth()*0.5f + 0.5f), 0, referenceFrame.getWidth());
    233 
    234 		// Fill left half - comparison to constant 0.5
    235 		for (int x = 0; x < half; x++)
    236 		{
    237 			float	xf		= ((float)x + 0.5f) / (float)referenceFrame.getWidth();
    238 			float	d		= depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
    239 			bool	dpass	= compare(m_compareFunc, d, constDepth*0.5f + 0.5f);
    240 
    241 			referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
    242 		}
    243 
    244 		// Fill right half - comparison to interpolated depth
    245 		for (int x = half; x < referenceFrame.getWidth(); x++)
    246 		{
    247 			float	xf		= ((float)x + 0.5f) / (float)referenceFrame.getWidth();
    248 			float	xh		= ((float)(x - half) + 0.5f) / (float)(referenceFrame.getWidth()-half);
    249 			float	rd		= 1.0f - (xh + yf) * 0.5f;
    250 			float	d		= depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
    251 			bool	dpass	= compare(m_compareFunc, d, rd);
    252 
    253 			referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
    254 		}
    255 	}
    256 
    257 	bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
    258 	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    259 							isOk ? "Pass"				: "Fail");
    260 	return STOP;
    261 }
    262 
    263 class DepthRangeWriteCase : public TestCase
    264 {
    265 public:
    266 							DepthRangeWriteCase		(Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar);
    267 							~DepthRangeWriteCase	(void);
    268 
    269 	IterateResult			iterate					(void);
    270 
    271 private:
    272 	const tcu::Vec4&		m_depthCoord;
    273 	const float				m_zNear;
    274 	const float				m_zFar;
    275 };
    276 
    277 DepthRangeWriteCase::DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar)
    278 	: TestCase			(context, name, desc)
    279 	, m_depthCoord		(depthCoord)
    280 	, m_zNear			(zNear)
    281 	, m_zFar			(zFar)
    282 {
    283 }
    284 
    285 DepthRangeWriteCase::~DepthRangeWriteCase (void)
    286 {
    287 }
    288 
    289 DepthRangeWriteCase::IterateResult DepthRangeWriteCase::iterate (void)
    290 {
    291 	TestLog&					log				= m_testCtx.getLog();
    292 	de::Random					rnd				(deStringHash(getName()));
    293 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderContext().getRenderTarget();
    294 	const int					viewportW		= de::min(128, renderTarget.getWidth());
    295 	const int					viewportH		= de::min(128, renderTarget.getHeight());
    296 	const int					viewportX		= rnd.getInt(0, renderTarget.getWidth()-viewportW);
    297 	const int					viewportY		= rnd.getInt(0, renderTarget.getHeight()-viewportH);
    298 	tcu::Surface				renderedFrame	(viewportW, viewportH);
    299 	tcu::Surface				referenceFrame	(viewportW, viewportH);
    300 	const int					numDepthSteps	= VISUALIZE_DEPTH_STEPS;
    301 	const float					depthStep		= 1.0f/(float)(numDepthSteps-1);
    302 
    303 	if (renderTarget.getDepthBits() == 0)
    304 		throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
    305 
    306 	const glu::ShaderProgram	program			(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));
    307 
    308 	if (!program.isOk())
    309 	{
    310 		log << program;
    311 		TCU_FAIL("Compile failed");
    312 	}
    313 
    314 	const int					colorLoc		= glGetUniformLocation(program.getProgram(), "u_color");
    315 	const int					posLoc			= glGetAttribLocation(program.getProgram(), "a_position");
    316 
    317 	m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage;
    318 
    319 	glViewport(viewportX, viewportY, viewportW, viewportH);
    320 	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    321 	glEnable(GL_DEPTH_TEST);
    322 	glUseProgram(program.getProgram());
    323 	glEnableVertexAttribArray(posLoc);
    324 
    325 	static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
    326 
    327 	// Render with depth range.
    328 	{
    329 		const float position[] =
    330 		{
    331 			-1.0f, -1.0f, m_depthCoord[0], 1.0f,
    332 			-1.0f, +1.0f, m_depthCoord[1], 1.0f,
    333 			+1.0f, -1.0f, m_depthCoord[2], 1.0f,
    334 			+1.0f, +1.0f, m_depthCoord[3], 1.0f
    335 		};
    336 
    337 		glDepthFunc(GL_ALWAYS);
    338 		glDepthRangef(m_zNear, m_zFar);
    339 		glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
    340 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
    341 		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
    342 		GLU_CHECK();
    343 	}
    344 
    345 	// Visualize by rendering full-screen quads with increasing depth and color.
    346 	{
    347 		glDepthFunc(GL_LEQUAL);
    348 		glDepthMask(GL_FALSE);
    349 		glDepthRangef(0.0f, 1.0f);
    350 
    351 		for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++)
    352 		{
    353 			float	f		= (float)stepNdx*depthStep;
    354 			float	depth	= f*2.0f - 1.0f;
    355 			Vec4	color	= Vec4(f, f, f, 1.0f);
    356 
    357 			float position[] =
    358 			{
    359 				-1.0f, -1.0f, depth, 1.0f,
    360 				-1.0f, +1.0f, depth, 1.0f,
    361 				+1.0f, -1.0f, depth, 1.0f,
    362 				+1.0f, +1.0f, depth, 1.0f
    363 			};
    364 
    365 			glUniform4fv(colorLoc, 1, color.getPtr());
    366 			glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
    367 			glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
    368 		}
    369 
    370 		GLU_CHECK();
    371 	}
    372 
    373 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
    374 
    375 	// Render reference.
    376 	for (int y = 0; y < referenceFrame.getHeight(); y++)
    377 	{
    378 		for (int x = 0; x < referenceFrame.getWidth(); x++)
    379 		{
    380 			float	xf		= ((float)x + 0.5f) / (float)referenceFrame.getWidth();
    381 			float	yf		= ((float)y + 0.5f) / (float)referenceFrame.getHeight();
    382 			float	d		= depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
    383 			int		step	= (int)deFloatFloor(d / depthStep);
    384 			int		col		= de::clamp(deRoundFloatToInt32((float)step*depthStep*255.0f), 0, 255);
    385 
    386 			referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff));
    387 		}
    388 	}
    389 
    390 	bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
    391 	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    392 							isOk ? "Pass"				: "Fail");
    393 	return STOP;
    394 }
    395 
    396 DepthRangeTests::DepthRangeTests (Context& context)
    397 	: TestCaseGroup(context, "depth_range", "glDepthRangef() tests")
    398 {
    399 }
    400 
    401 DepthRangeTests::~DepthRangeTests (void)
    402 {
    403 }
    404 
    405 void DepthRangeTests::init (void)
    406 {
    407 	static const struct
    408 	{
    409 		const char*			name;
    410 		const char*			desc;
    411 		const tcu::Vec4		depthCoord;
    412 		const float			zNear;
    413 		const float			zFar;
    414 	} cases[] =
    415 	{
    416 		{ "default",		"Default depth range",		tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		1.0f },
    417 		{ "reverse",		"Reversed default range",	tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f,		0.0f },
    418 		{ "zero_to_half",	"From 0 to 0.5",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		0.5f },
    419 		{ "half_to_one",	"From 0.5 to 1",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.5f,		1.0f },
    420 		{ "half_to_zero",	"From 0.5 to 0",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.5f,		0.0f },
    421 		{ "one_to_half",	"From 1 to 0.5",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f,		0.5f },
    422 		{ "third_to_0_8",	"From 1/3 to 0.8",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f/3.0f,	0.8f },
    423 		{ "0_8_to_third",	"From 0.8 to 1/3",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.8f,		1.0f/3.0f },
    424 		{ "zero_to_zero",	"From 0 to 0",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		0.0f },
    425 		{ "half_to_half",	"From 0.5 to 0.5",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.5f,		0.5f },
    426 		{ "one_to_one",		"From 1 to 1",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f,		1.0f },
    427 		{ "clamp_near",		"From -1 to 1",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	-1.0f,		1.0f },
    428 		{ "clamp_far",		"From 0 to 2",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		2.0 },
    429 		{ "clamp_both",		"From -1 to 2",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	-1.0,		2.0 }
    430 	};
    431 
    432 	// .write
    433 	tcu::TestCaseGroup* writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests");
    434 	addChild(writeGroup);
    435 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
    436 		writeGroup->addChild(new DepthRangeWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar));
    437 
    438 	// .compare
    439 	tcu::TestCaseGroup* compareGroup = new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison");
    440 	addChild(compareGroup);
    441 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
    442 		compareGroup->addChild(new DepthRangeCompareCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar, GL_LESS));
    443 }
    444 
    445 } // Functional
    446 } // gles3
    447 } // deqp
    448