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 {
Cleardeqp::gles2::Functional::__anon203b99620111::Clear68 	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 
getDepthFormat(int depthBits)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 
getStencilFormat(int stencilBits)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 
DepthStencilClearCase(Context & context,const char * name,const char * description,int numIters,int numClears,bool depth,bool stencil,bool scissor,bool masked)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 
~DepthStencilClearCase(void)158 DepthStencilClearCase::~DepthStencilClearCase (void)
159 {
160 	DepthStencilClearCase::deinit();
161 }
162 
init(void)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 
deinit(void)193 void DepthStencilClearCase::deinit (void)
194 {
195 	delete m_visProgram;
196 	m_visProgram = DE_NULL;
197 }
198 
iterate(void)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 
generateClears(vector<Clear> & clears,deUint32 seed)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 
renderGL(tcu::Surface & dst,const vector<Clear> & clears)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 
renderReference(tcu::Surface & dst,const vector<Clear> & clears)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 
DepthStencilClearTests(Context & context)496 DepthStencilClearTests::DepthStencilClearTests (Context& context)
497 	: TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
498 {
499 }
500 
init(void)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