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 Depth and stencil clear tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fDepthStencilClearTests.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 gles2
     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 			"attribute highp vec4 a_position;\n"
    170 			"void main (void)\n"
    171 			"{\n"
    172 			"	gl_Position = a_position;\n"
    173 			"}\n",
    174 
    175 			// Fragment shader.
    176 			"uniform mediump vec4 u_color;\n"
    177 			"void main (void)\n"
    178 			"{\n"
    179 			"	gl_FragColor = u_color;\n"
    180 			"}\n"));
    181 
    182 	if (!m_visProgram->isOk())
    183 	{
    184 		log << *m_visProgram;
    185 		delete m_visProgram;
    186 		m_visProgram = DE_NULL;
    187 		TCU_FAIL("Compile failed");
    188 	}
    189 
    190 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    191 }
    192 
    193 void DepthStencilClearCase::deinit (void)
    194 {
    195 	delete m_visProgram;
    196 	m_visProgram = DE_NULL;
    197 }
    198 
    199 DepthStencilClearCase::IterateResult DepthStencilClearCase::iterate (void)
    200 {
    201 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
    202 	int							width			= renderTarget.getWidth();
    203 	int							height			= renderTarget.getHeight();
    204 	tcu::Surface				result			(width, height);
    205 	tcu::Surface				reference		(width, height);
    206 	tcu::RGBA					threshold		= renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
    207 	vector<Clear>				clears;
    208 
    209 	if ((m_testDepth && renderTarget.getDepthBits() == 0) ||
    210 		(m_testStencil && renderTarget.getStencilBits() == 0))
    211 		throw tcu::NotSupportedError("No depth/stencil buffers", "", __FILE__, __LINE__);
    212 
    213 	generateClears(clears, deStringHash(getName())^deInt32Hash(m_curIter));
    214 	renderGL(result, clears);
    215 	renderReference(reference, clears);
    216 
    217 	bool	isLastIter		= m_curIter+1 == m_numIters;
    218 	bool	isOk			= tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, isLastIter ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
    219 
    220 	if (!isOk)
    221 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    222 
    223 	m_curIter += 1;
    224 	return isLastIter || !isOk ? STOP : CONTINUE;
    225 }
    226 
    227 void DepthStencilClearCase::generateClears (vector<Clear>& clears, deUint32 seed)
    228 {
    229 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderContext().getRenderTarget();
    230 	int							width			= renderTarget.getWidth();
    231 	int							height			= renderTarget.getHeight();
    232 	de::Random					rnd				(seed);
    233 
    234 	clears.resize(m_numClears);
    235 
    236 	for (vector<Clear>::iterator clear = clears.begin(); clear != clears.end(); clear++)
    237 	{
    238 		if (m_testScissor)
    239 		{
    240 			int w = rnd.getInt(1, width);
    241 			int h = rnd.getInt(1, height);
    242 			int x = rnd.getInt(0, width-w);
    243 			int y = rnd.getInt(0, height-h);
    244 
    245 			clear->useScissor	= true; // \todo [pyry] Should we randomize?
    246 			clear->scissor		= tcu::IVec4(x, y, w, h);
    247 		}
    248 		else
    249 			clear->useScissor = false;
    250 
    251 		clear->clearDepth	= rnd.getFloat(-0.2f, 1.2f);
    252 		clear->clearStencil	= rnd.getUint32();
    253 
    254 		clear->depthMask	= m_masked ? rnd.getBool()		: true;
    255 		clear->stencilMask	= m_masked ? rnd.getUint32()	: 0xffffffffu;
    256 
    257 		if (m_testDepth && m_testStencil)
    258 		{
    259 			switch (rnd.getInt(0, 2))
    260 			{
    261 				case 0: clear->clearMask = GL_DEPTH_BUFFER_BIT;							break;
    262 				case 1: clear->clearMask = GL_STENCIL_BUFFER_BIT;						break;
    263 				case 2: clear->clearMask = GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT;	break;
    264 			}
    265 		}
    266 		else if (m_testDepth)
    267 			clear->clearMask = GL_DEPTH_BUFFER_BIT;
    268 		else
    269 		{
    270 			DE_ASSERT(m_testStencil);
    271 			clear->clearMask = GL_STENCIL_BUFFER_BIT;
    272 		}
    273 	}
    274 }
    275 
    276 void DepthStencilClearCase::renderGL (tcu::Surface& dst, const vector<Clear>& clears)
    277 {
    278 	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
    279 	int							colorLoc		= gl.getUniformLocation(m_visProgram->getProgram(), "u_color");
    280 	int							positionLoc		= gl.getAttribLocation(m_visProgram->getProgram(), "a_position");
    281 	static const deUint8		indices[]		= { 0, 1, 2, 2, 1, 3 };
    282 
    283 	// Clear with default values.
    284 	gl.clearDepthf	(1.0f);
    285 	gl.clearStencil	(0);
    286 	gl.clearColor	(1.0f, 0.0f, 0.0f, 1.0f);
    287 	gl.clear		(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    288 
    289 	GLU_EXPECT_NO_ERROR(gl.getError(), "Before clears");
    290 
    291 	for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
    292 	{
    293 		if (clear->useScissor)
    294 		{
    295 			gl.enable(GL_SCISSOR_TEST);
    296 			gl.scissor(clear->scissor.x(), clear->scissor.y(), clear->scissor.z(), clear->scissor.w());
    297 		}
    298 
    299 		// Clear values.
    300 		gl.clearDepthf	(clear->clearDepth);
    301 		gl.clearStencil	(clear->clearStencil);
    302 
    303 		// Masks.
    304 		gl.depthMask	(clear->depthMask ? GL_TRUE : GL_FALSE);
    305 		gl.stencilMask	(clear->stencilMask);
    306 
    307 		// Execute clear.
    308 		gl.clear		(clear->clearMask);
    309 
    310 		if (clear->useScissor)
    311 			gl.disable(GL_SCISSOR_TEST);
    312 	}
    313 
    314 	// Restore default masks.
    315 	gl.depthMask	(GL_TRUE);
    316 	gl.stencilMask	(0xffffffffu);
    317 
    318 	GLU_EXPECT_NO_ERROR(gl.getError(), "After clears");
    319 
    320 	gl.useProgram				(m_visProgram->getProgram());
    321 	gl.enableVertexAttribArray	(positionLoc);
    322 
    323 	// Visualize depth / stencil buffers.
    324 	if (m_testDepth)
    325 	{
    326 		int		numSteps	= DEPTH_STEPS;
    327 		float	step		= 2.0f / (float)numSteps;
    328 
    329 		gl.enable	(GL_DEPTH_TEST);
    330 		gl.depthFunc(GL_LESS);
    331 		gl.depthMask(GL_FALSE);
    332 		gl.colorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
    333 
    334 		for (int ndx = 0; ndx < numSteps; ndx++)
    335 		{
    336 			float	d		= -1.0f + step*(float)ndx;
    337 			float	c		= (float)ndx / (float)(numSteps-1);
    338 			float	pos[]	=
    339 			{
    340 				-1.0f, -1.0f, d,
    341 				-1.0f,  1.0f, d,
    342 				 1.0f, -1.0f, d,
    343 				 1.0f,  1.0f, d
    344 			};
    345 
    346 			gl.uniform4f			(colorLoc, 0.0f, 0.0f, c, 1.0f);
    347 			gl.vertexAttribPointer	(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, &pos[0]);
    348 			gl.drawElements			(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
    349 		}
    350 
    351 		gl.disable	(GL_DEPTH_TEST);
    352 		gl.depthMask(GL_TRUE);
    353 
    354 		GLU_EXPECT_NO_ERROR(gl.getError(), "After depth visualization");
    355 	}
    356 
    357 	if (m_testStencil)
    358 	{
    359 		int		numSteps	= STENCIL_STEPS;
    360 		int		numValues	= (1 << TestCase::m_context.getRenderContext().getRenderTarget().getStencilBits()); // 2^bits
    361 		int		step		= numValues / numSteps;
    362 
    363 		gl.enable		(GL_STENCIL_TEST);
    364 		gl.stencilOp	(GL_KEEP, GL_KEEP, GL_KEEP);
    365 		gl.colorMask	(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
    366 
    367 		static const float pos[] =
    368 		{
    369 			-1.0f, -1.0f,
    370 			-1.0f,  1.0f,
    371 			 1.0f, -1.0f,
    372 			 1.0f,  1.0f
    373 		};
    374 		gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &pos[0]);
    375 
    376 		for (int ndx = 0; ndx < numSteps; ndx++)
    377 		{
    378 			int		s	= step*ndx;
    379 			float	c	= (float)ndx / (float)(numSteps-1);
    380 
    381 			gl.stencilFunc	(GL_LEQUAL, s, 0xffu);
    382 			gl.uniform4f	(colorLoc, 0.0f, c, 0.0f, 1.0f);
    383 			gl.drawElements	(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
    384 		}
    385 
    386 		gl.disable(GL_STENCIL_TEST);
    387 
    388 		GLU_EXPECT_NO_ERROR(gl.getError(), "After stencil visualization");
    389 	}
    390 
    391 	// Restore color mask (changed by visualization).
    392 	gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    393 
    394 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
    395 }
    396 
    397 void DepthStencilClearCase::renderReference (tcu::Surface& dst, const vector<Clear>& clears)
    398 {
    399 	glu::RenderContext&			renderCtx		= TestCase::m_context.getRenderContext();
    400 	const tcu::RenderTarget&	renderTarget	= renderCtx.getRenderTarget();
    401 
    402 	// Clear surface to red.
    403 	tcu::clear(dst.getAccess(), tcu::RGBA::red().toVec());
    404 
    405 	if (m_testDepth)
    406 	{
    407 		// Simulated depth buffer span.
    408 		tcu::TextureLevel		depthBufRow		(getDepthFormat(renderTarget.getDepthBits()), dst.getWidth(), 1, 1);
    409 		tcu::PixelBufferAccess	rowAccess		= depthBufRow.getAccess();
    410 
    411 		for (int y = 0; y < dst.getHeight(); y++)
    412 		{
    413 			// Clear to default value.
    414 			for (int x = 0; x < rowAccess.getWidth(); x++)
    415 				rowAccess.setPixel(Vec4(1.0f), x, 0);
    416 
    417 			// Execute clears.
    418 			for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
    419 			{
    420 				// Clear / mask test.
    421 				if ((clear->clearMask & GL_DEPTH_BUFFER_BIT) == 0 || !clear->depthMask)
    422 					continue;
    423 
    424 				tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
    425 
    426 				// Intersection test.
    427 				if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w()))
    428 					continue;
    429 
    430 				for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++)
    431 					rowAccess.setPixDepth(de::clamp(clear->clearDepth, 0.0f, 1.0f), x, 0);
    432 			}
    433 
    434 			// Map to colors.
    435 			for (int x = 0; x < dst.getWidth(); x++)
    436 			{
    437 				float		depth		= rowAccess.getPixDepth(x, 0);
    438 				float		step		= deFloatFloor(depth * (float)DEPTH_STEPS) / (float)(DEPTH_STEPS-1);
    439 				tcu::RGBA	oldColor	= dst.getPixel(x, y);
    440 				tcu::RGBA	newColor	= tcu::RGBA(oldColor.getRed(), oldColor.getGreen(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getAlpha());
    441 
    442 				dst.setPixel(x, y, newColor);
    443 			}
    444 		}
    445 	}
    446 
    447 	if (m_testStencil)
    448 	{
    449 		// Simulated stencil buffer span.
    450 		int						stencilBits		= renderTarget.getStencilBits();
    451 		tcu::TextureLevel		depthBufRow		(getStencilFormat(stencilBits), dst.getWidth(), 1, 1);
    452 		tcu::PixelBufferAccess	rowAccess		= depthBufRow.getAccess();
    453 		deUint32				bufMask			= (1u<<stencilBits)-1;
    454 
    455 		for (int y = 0; y < dst.getHeight(); y++)
    456 		{
    457 			// Clear to default value.
    458 			for (int x = 0; x < rowAccess.getWidth(); x++)
    459 				rowAccess.setPixel(tcu::UVec4(0), x, 0);
    460 
    461 			// Execute clears.
    462 			for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
    463 			{
    464 				// Clear / mask test.
    465 				if ((clear->clearMask & GL_STENCIL_BUFFER_BIT) == 0 || clear->stencilMask == 0)
    466 					continue;
    467 
    468 				tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
    469 
    470 				// Intersection test.
    471 				if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w()))
    472 					continue;
    473 
    474 				for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++)
    475 				{
    476 					deUint32	oldVal	= rowAccess.getPixStencil(x, 0);
    477 					deUint32	newVal	= ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask;
    478 					rowAccess.setPixStencil(newVal, x, 0);
    479 				}
    480 			}
    481 
    482 			// Map to colors.
    483 			for (int x = 0; x < dst.getWidth(); x++)
    484 			{
    485 				deUint32	stencil		= rowAccess.getPixStencil(x, 0);
    486 				float		step		= (float)(stencil / ((1u<<stencilBits) / (deUint32)STENCIL_STEPS)) / (float)(STENCIL_STEPS-1);
    487 				tcu::RGBA	oldColor	= dst.getPixel(x, y);
    488 				tcu::RGBA	newColor	= tcu::RGBA(oldColor.getRed(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getBlue(), oldColor.getAlpha());
    489 
    490 				dst.setPixel(x, y, newColor);
    491 			}
    492 		}
    493 	}
    494 }
    495 
    496 DepthStencilClearTests::DepthStencilClearTests (Context& context)
    497 	: TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
    498 {
    499 }
    500 
    501 void DepthStencilClearTests::init (void)
    502 {
    503 	//																					iters	clears	depth	stencil	scissor	masked
    504 	addChild(new DepthStencilClearCase(m_context, "depth",							"",	4,		2,		true,	false,	false,	false));
    505 	addChild(new DepthStencilClearCase(m_context, "depth_scissored",				"",	4,		16,		true,	false,	true,	false));
    506 	addChild(new DepthStencilClearCase(m_context, "depth_scissored_masked",			"",	4,		16,		true,	false,	true,	true));
    507 
    508 	addChild(new DepthStencilClearCase(m_context, "stencil",						"",	4,		2,		false,	true,	false,	false));
    509 	addChild(new DepthStencilClearCase(m_context, "stencil_masked",					"",	4,		8,		false,	true,	false,	true));
    510 	addChild(new DepthStencilClearCase(m_context, "stencil_scissored",				"",	4,		16,		false,	true,	true,	false));
    511 	addChild(new DepthStencilClearCase(m_context, "stencil_scissored_masked",		"",	4,		16,		false,	true,	true,	true));
    512 
    513 	addChild(new DepthStencilClearCase(m_context, "depth_stencil",					"",	4,		2,		true,	true,	false,	false));
    514 	addChild(new DepthStencilClearCase(m_context, "depth_stencil_masked",			"",	4,		8,		true,	true,	false,	true));
    515 	addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored",		"",	4,		16,		true,	true,	true,	false));
    516 	addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored_masked",	"",	4,		16,		true,	true,	true,	true));
    517 }
    518 
    519 } // Functional
    520 } // gles2
    521 } // deqp
    522