Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Depth and stencil clear tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fDepthStencilClearTests.hpp"
     25 
     26 #include "gluShaderProgram.hpp"
     27 #include "gluPixelTransfer.hpp"
     28 #include "gluRenderContext.hpp"
     29 
     30 #include "tcuTestLog.hpp"
     31 #include "tcuTexture.hpp"
     32 #include "tcuTextureUtil.hpp"
     33 #include "tcuImageCompare.hpp"
     34 #include "tcuSurface.hpp"
     35 #include "tcuRenderTarget.hpp"
     36 
     37 #include "deRandom.hpp"
     38 #include "deMath.h"
     39 #include "deString.h"
     40 
     41 #include "glwFunctions.hpp"
     42 #include "glwEnums.hpp"
     43 
     44 namespace deqp
     45 {
     46 namespace gles3
     47 {
     48 namespace Functional
     49 {
     50 
     51 using tcu::Vec3;
     52 using tcu::Vec4;
     53 using tcu::TestLog;
     54 using std::string;
     55 using std::vector;
     56 
     57 namespace
     58 {
     59 
     60 enum
     61 {
     62 	STENCIL_STEPS	= 32,
     63 	DEPTH_STEPS		= 32
     64 };
     65 
     66 struct Clear
     67 {
     68 	Clear (void)
     69 		: clearMask			(0)
     70 		, clearDepth		(0.0f)
     71 		, clearStencil		(0)
     72 		, useScissor		(false)
     73 		, scissor			(0, 0, 0, 0)
     74 		, depthMask			(false)
     75 		, stencilMask		(0)
     76 	{
     77 	}
     78 
     79 	deUint32	clearMask;
     80 	float		clearDepth;
     81 	int			clearStencil;
     82 
     83 	bool		useScissor;
     84 	tcu::IVec4	scissor;
     85 
     86 	bool		depthMask;
     87 	deUint32	stencilMask;
     88 };
     89 
     90 tcu::TextureFormat getDepthFormat (int depthBits)
     91 {
     92 	switch (depthBits)
     93 	{
     94 		case 8:		return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8);
     95 		case 16:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
     96 		case 24:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT24);
     97 		case 32:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
     98 		default:
     99 			TCU_FAIL("Can't map depth buffer format");
    100 	}
    101 }
    102 
    103 tcu::TextureFormat getStencilFormat (int stencilBits)
    104 {
    105 	switch (stencilBits)
    106 	{
    107 		case 8:		return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
    108 		case 16:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT16);
    109 		case 24:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT24);
    110 		case 32:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32);
    111 		default:
    112 			TCU_FAIL("Can't map depth buffer format");
    113 	}
    114 }
    115 
    116 } // anonymous.
    117 
    118 class DepthStencilClearCase : public TestCase
    119 {
    120 public:
    121 								DepthStencilClearCase	(Context& context, const char* name, const char* description, int numIters, int numClears, bool depth, bool stencil, bool scissor, bool masked);
    122 								~DepthStencilClearCase	(void);
    123 
    124 	void						init					(void);
    125 	void						deinit					(void);
    126 
    127 	IterateResult				iterate					(void);
    128 
    129 private:
    130 	void						generateClears			(vector<Clear>& dst, deUint32 seed);
    131 	void						renderGL				(tcu::Surface& dst, const vector<Clear>& clears);
    132 	void						renderReference			(tcu::Surface& dst, const vector<Clear>& clears);
    133 
    134 	bool						m_testDepth;
    135 	bool						m_testStencil;
    136 	bool						m_testScissor;
    137 	bool						m_masked;
    138 	int							m_numIters;
    139 	int							m_numClears;
    140 	int							m_curIter;
    141 
    142 	glu::ShaderProgram*			m_visProgram;
    143 };
    144 
    145 DepthStencilClearCase::DepthStencilClearCase (Context& context, const char* name, const char* description, int numIters, int numClears, bool depth, bool stencil, bool scissor, bool masked)
    146 	: TestCase			(context, name, description)
    147 	, m_testDepth		(depth)
    148 	, m_testStencil		(stencil)
    149 	, m_testScissor		(scissor)
    150 	, m_masked			(masked)
    151 	, m_numIters		(numIters)
    152 	, m_numClears		(numClears)
    153 	, m_curIter			(0)
    154 	, m_visProgram		(DE_NULL)
    155 {
    156 }
    157 
    158 DepthStencilClearCase::~DepthStencilClearCase (void)
    159 {
    160 	DepthStencilClearCase::deinit();
    161 }
    162 
    163 void DepthStencilClearCase::init (void)
    164 {
    165 	TestLog& log = m_testCtx.getLog();
    166 
    167 	m_visProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
    168 			// Vertex shader.
    169 			"#version 300 es\n"
    170 			"in highp vec4 a_position;\n"
    171 			"void main (void)\n"
    172 			"{\n"
    173 			"	gl_Position = a_position;\n"
    174 			"}\n",
    175 
    176 			// Fragment shader.
    177 			"#version 300 es\n"
    178 			"uniform mediump vec4 u_color;\n"
    179 			"layout(location = 0) out mediump vec4 o_color;\n"
    180 			"void main (void)\n"
    181 			"{\n"
    182 			"	o_color = u_color;\n"
    183 			"}\n"));
    184 
    185 	if (!m_visProgram->isOk())
    186 	{
    187 		log << *m_visProgram;
    188 		delete m_visProgram;
    189 		m_visProgram = DE_NULL;
    190 		TCU_FAIL("Compile failed");
    191 	}
    192 
    193 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    194 }
    195 
    196 void DepthStencilClearCase::deinit (void)
    197 {
    198 	delete m_visProgram;
    199 	m_visProgram = DE_NULL;
    200 }
    201 
    202 DepthStencilClearCase::IterateResult DepthStencilClearCase::iterate (void)
    203 {
    204 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
    205 	int							width			= renderTarget.getWidth();
    206 	int							height			= renderTarget.getHeight();
    207 	tcu::Surface				result			(width, height);
    208 	tcu::Surface				reference		(width, height);
    209 	tcu::RGBA					threshold		= renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
    210 	vector<Clear>				clears;
    211 
    212 	if ((m_testDepth && renderTarget.getDepthBits() == 0) ||
    213 		(m_testStencil && renderTarget.getStencilBits() == 0))
    214 		throw tcu::NotSupportedError("No depth/stencil buffers", "", __FILE__, __LINE__);
    215 
    216 	generateClears(clears, deStringHash(getName())^deInt32Hash(m_curIter));
    217 	renderGL(result, clears);
    218 	renderReference(reference, clears);
    219 
    220 	bool	isLastIter		= m_curIter+1 == m_numIters;
    221 	bool	isOk			= tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, isLastIter ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
    222 
    223 	if (!isOk)
    224 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    225 
    226 	m_curIter += 1;
    227 	return isLastIter || !isOk ? STOP : CONTINUE;
    228 }
    229 
    230 void DepthStencilClearCase::generateClears (vector<Clear>& clears, deUint32 seed)
    231 {
    232 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderContext().getRenderTarget();
    233 	int							width			= renderTarget.getWidth();
    234 	int							height			= renderTarget.getHeight();
    235 	de::Random					rnd				(seed);
    236 
    237 	clears.resize(m_numClears);
    238 
    239 	for (vector<Clear>::iterator clear = clears.begin(); clear != clears.end(); clear++)
    240 	{
    241 		if (m_testScissor)
    242 		{
    243 			int w = rnd.getInt(1, width);
    244 			int h = rnd.getInt(1, height);
    245 			int x = rnd.getInt(0, width-w);
    246 			int y = rnd.getInt(0, height-h);
    247 
    248 			clear->useScissor	= true; // \todo [pyry] Should we randomize?
    249 			clear->scissor		= tcu::IVec4(x, y, w, h);
    250 		}
    251 		else
    252 			clear->useScissor = false;
    253 
    254 		clear->clearDepth	= rnd.getFloat(-0.2f, 1.2f);
    255 		clear->clearStencil	= rnd.getUint32();
    256 
    257 		clear->depthMask	= m_masked ? rnd.getBool()		: true;
    258 		clear->stencilMask	= m_masked ? rnd.getUint32()	: 0xffffffffu;
    259 
    260 		if (m_testDepth && m_testStencil)
    261 		{
    262 			switch (rnd.getInt(0, 2))
    263 			{
    264 				case 0: clear->clearMask = GL_DEPTH_BUFFER_BIT;							break;
    265 				case 1: clear->clearMask = GL_STENCIL_BUFFER_BIT;						break;
    266 				case 2: clear->clearMask = GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT;	break;
    267 			}
    268 		}
    269 		else if (m_testDepth)
    270 			clear->clearMask = GL_DEPTH_BUFFER_BIT;
    271 		else
    272 		{
    273 			DE_ASSERT(m_testStencil);
    274 			clear->clearMask = GL_STENCIL_BUFFER_BIT;
    275 		}
    276 	}
    277 }
    278 
    279 void DepthStencilClearCase::renderGL (tcu::Surface& dst, const vector<Clear>& clears)
    280 {
    281 	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
    282 	int							colorLoc		= gl.getUniformLocation(m_visProgram->getProgram(), "u_color");
    283 	int							positionLoc		= gl.getAttribLocation(m_visProgram->getProgram(), "a_position");
    284 	static const deUint8		indices[]		= { 0, 1, 2, 2, 1, 3 };
    285 
    286 	// Clear with default values.
    287 	gl.clearDepthf	(1.0f);
    288 	gl.clearStencil	(0);
    289 	gl.clearColor	(1.0f, 0.0f, 0.0f, 1.0f);
    290 	gl.clear		(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    291 
    292 	GLU_EXPECT_NO_ERROR(gl.getError(), "Before clears");
    293 
    294 	for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
    295 	{
    296 		if (clear->useScissor)
    297 		{
    298 			gl.enable(GL_SCISSOR_TEST);
    299 			gl.scissor(clear->scissor.x(), clear->scissor.y(), clear->scissor.z(), clear->scissor.w());
    300 		}
    301 
    302 		// Clear values.
    303 		gl.clearDepthf	(clear->clearDepth);
    304 		gl.clearStencil	(clear->clearStencil);
    305 
    306 		// Masks.
    307 		gl.depthMask	(clear->depthMask ? GL_TRUE : GL_FALSE);
    308 		gl.stencilMask	(clear->stencilMask);
    309 
    310 		// Execute clear.
    311 		gl.clear		(clear->clearMask);
    312 
    313 		if (clear->useScissor)
    314 			gl.disable(GL_SCISSOR_TEST);
    315 	}
    316 
    317 	// Restore default masks.
    318 	gl.depthMask	(GL_TRUE);
    319 	gl.stencilMask	(0xffffffffu);
    320 
    321 	GLU_EXPECT_NO_ERROR(gl.getError(), "After clears");
    322 
    323 	gl.useProgram				(m_visProgram->getProgram());
    324 	gl.enableVertexAttribArray	(positionLoc);
    325 
    326 	// Visualize depth / stencil buffers.
    327 	if (m_testDepth)
    328 	{
    329 		int		numSteps	= DEPTH_STEPS;
    330 		float	step		= 2.0f / numSteps;
    331 
    332 		gl.enable	(GL_DEPTH_TEST);
    333 		gl.depthFunc(GL_LESS);
    334 		gl.depthMask(GL_FALSE);
    335 		gl.colorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
    336 
    337 		for (int ndx = 0; ndx < numSteps; ndx++)
    338 		{
    339 			float	d		= -1.0f + step*ndx;
    340 			float	c		= (float)ndx / (float)(numSteps-1);
    341 			float	pos[]	=
    342 			{
    343 				-1.0f, -1.0f, d,
    344 				-1.0f,  1.0f, d,
    345 				 1.0f, -1.0f, d,
    346 				 1.0f,  1.0f, d
    347 			};
    348 
    349 			gl.uniform4f			(colorLoc, 0.0f, 0.0f, c, 1.0f);
    350 			gl.vertexAttribPointer	(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, &pos[0]);
    351 			gl.drawElements			(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
    352 		}
    353 
    354 		gl.disable	(GL_DEPTH_TEST);
    355 		gl.depthMask(GL_TRUE);
    356 
    357 		GLU_EXPECT_NO_ERROR(gl.getError(), "After depth visualization");
    358 	}
    359 
    360 	if (m_testStencil)
    361 	{
    362 		int		numSteps	= STENCIL_STEPS;
    363 		int		numValues	= (1 << TestCase::m_context.getRenderContext().getRenderTarget().getStencilBits()); // 2^bits
    364 		int		step		= numValues / numSteps;
    365 
    366 		gl.enable		(GL_STENCIL_TEST);
    367 		gl.stencilOp	(GL_KEEP, GL_KEEP, GL_KEEP);
    368 		gl.colorMask	(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
    369 
    370 		static const float pos[] =
    371 		{
    372 			-1.0f, -1.0f,
    373 			-1.0f,  1.0f,
    374 			 1.0f, -1.0f,
    375 			 1.0f,  1.0f
    376 		};
    377 		gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &pos[0]);
    378 
    379 		for (int ndx = 0; ndx < numSteps; ndx++)
    380 		{
    381 			int		s	= step*ndx;
    382 			float	c	= (float)ndx / (float)(numSteps-1);
    383 
    384 			gl.stencilFunc	(GL_LEQUAL, s, 0xffu);
    385 			gl.uniform4f	(colorLoc, 0.0f, c, 0.0f, 1.0f);
    386 			gl.drawElements	(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
    387 		}
    388 
    389 		gl.disable(GL_STENCIL_TEST);
    390 
    391 		GLU_EXPECT_NO_ERROR(gl.getError(), "After stencil visualization");
    392 	}
    393 
    394 	// Restore color mask (changed by visualization).
    395 	gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    396 
    397 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
    398 }
    399 
    400 void DepthStencilClearCase::renderReference (tcu::Surface& dst, const vector<Clear>& clears)
    401 {
    402 	glu::RenderContext&			renderCtx		= TestCase::m_context.getRenderContext();
    403 	const tcu::RenderTarget&	renderTarget	= renderCtx.getRenderTarget();
    404 
    405 	// Clear surface to red.
    406 	tcu::clear(dst.getAccess(), tcu::RGBA::red.toVec());
    407 
    408 	if (m_testDepth)
    409 	{
    410 		// Simulated depth buffer span.
    411 		tcu::TextureLevel		depthBufRow		(getDepthFormat(renderTarget.getDepthBits()), dst.getWidth(), 1, 1);
    412 		tcu::PixelBufferAccess	rowAccess		= depthBufRow.getAccess();
    413 
    414 		for (int y = 0; y < dst.getHeight(); y++)
    415 		{
    416 			// Clear to default value.
    417 			for (int x = 0; x < rowAccess.getWidth(); x++)
    418 				rowAccess.setPixel(Vec4(1.0f), x, 0);
    419 
    420 			// Execute clears.
    421 			for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
    422 			{
    423 				// Clear / mask test.
    424 				if ((clear->clearMask & GL_DEPTH_BUFFER_BIT) == 0 || !clear->depthMask)
    425 					continue;
    426 
    427 				tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
    428 
    429 				// Intersection test.
    430 				if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w()))
    431 					continue;
    432 
    433 				for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++)
    434 					rowAccess.setPixDepth(de::clamp(clear->clearDepth, 0.0f, 1.0f), x, 0);
    435 			}
    436 
    437 			// Map to colors.
    438 			for (int x = 0; x < dst.getWidth(); x++)
    439 			{
    440 				float		depth		= rowAccess.getPixDepth(x, 0);
    441 				float		step		= deFloatFloor(depth * (float)DEPTH_STEPS) / (float)(DEPTH_STEPS-1);
    442 				tcu::RGBA	oldColor	= dst.getPixel(x, y);
    443 				tcu::RGBA	newColor	= tcu::RGBA(oldColor.getRed(), oldColor.getGreen(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getAlpha());
    444 
    445 				dst.setPixel(x, y, newColor);
    446 			}
    447 		}
    448 	}
    449 
    450 	if (m_testStencil)
    451 	{
    452 		// Simulated stencil buffer span.
    453 		int						stencilBits		= renderTarget.getStencilBits();
    454 		tcu::TextureLevel		depthBufRow		(getStencilFormat(stencilBits), dst.getWidth(), 1, 1);
    455 		tcu::PixelBufferAccess	rowAccess		= depthBufRow.getAccess();
    456 		deUint32				bufMask			= (1u<<stencilBits)-1;
    457 
    458 		for (int y = 0; y < dst.getHeight(); y++)
    459 		{
    460 			// Clear to default value.
    461 			for (int x = 0; x < rowAccess.getWidth(); x++)
    462 				rowAccess.setPixel(tcu::UVec4(0), x, 0);
    463 
    464 			// Execute clears.
    465 			for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
    466 			{
    467 				// Clear / mask test.
    468 				if ((clear->clearMask & GL_STENCIL_BUFFER_BIT) == 0 || clear->stencilMask == 0)
    469 					continue;
    470 
    471 				tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
    472 
    473 				// Intersection test.
    474 				if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w()))
    475 					continue;
    476 
    477 				for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++)
    478 				{
    479 					deUint32	oldVal	= rowAccess.getPixStencil(x, 0);
    480 					deUint32	newVal	= ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask;
    481 					rowAccess.setPixStencil(newVal, x, 0);
    482 				}
    483 			}
    484 
    485 			// Map to colors.
    486 			for (int x = 0; x < dst.getWidth(); x++)
    487 			{
    488 				deUint32	stencil		= rowAccess.getPixStencil(x, 0);
    489 				float		step		= (float)(stencil / ((1u<<stencilBits) / (deUint32)STENCIL_STEPS)) / (float)(STENCIL_STEPS-1);
    490 				tcu::RGBA	oldColor	= dst.getPixel(x, y);
    491 				tcu::RGBA	newColor	= tcu::RGBA(oldColor.getRed(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getBlue(), oldColor.getAlpha());
    492 
    493 				dst.setPixel(x, y, newColor);
    494 			}
    495 		}
    496 	}
    497 }
    498 
    499 DepthStencilClearTests::DepthStencilClearTests (Context& context)
    500 	: TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
    501 {
    502 }
    503 
    504 void DepthStencilClearTests::init (void)
    505 {
    506 	//																					iters	clears	depth	stencil	scissor	masked
    507 	addChild(new DepthStencilClearCase(m_context, "depth",							"",	4,		2,		true,	false,	false,	false));
    508 	addChild(new DepthStencilClearCase(m_context, "depth_scissored",				"",	4,		16,		true,	false,	true,	false));
    509 	addChild(new DepthStencilClearCase(m_context, "depth_scissored_masked",			"",	4,		16,		true,	false,	true,	true));
    510 
    511 	addChild(new DepthStencilClearCase(m_context, "stencil",						"",	4,		2,		false,	true,	false,	false));
    512 	addChild(new DepthStencilClearCase(m_context, "stencil_masked",					"",	4,		8,		false,	true,	false,	true));
    513 	addChild(new DepthStencilClearCase(m_context, "stencil_scissored",				"",	4,		16,		false,	true,	true,	false));
    514 	addChild(new DepthStencilClearCase(m_context, "stencil_scissored_masked",		"",	4,		16,		false,	true,	true,	true));
    515 
    516 	addChild(new DepthStencilClearCase(m_context, "depth_stencil",					"",	4,		2,		true,	true,	false,	false));
    517 	addChild(new DepthStencilClearCase(m_context, "depth_stencil_masked",			"",	4,		8,		true,	true,	false,	true));
    518 	addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored",		"",	4,		16,		true,	true,	true,	false));
    519 	addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored_masked",	"",	4,		16,		true,	true,	true,	true));
    520 }
    521 
    522 } // Functional
    523 } // gles3
    524 } // deqp
    525