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
44namespace deqp
45{
46namespace gles2
47{
48namespace Functional
49{
50
51using tcu::Vec3;
52using tcu::Vec4;
53using tcu::TestLog;
54using std::string;
55using std::vector;
56
57namespace
58{
59
60enum
61{
62	STENCIL_STEPS	= 32,
63	DEPTH_STEPS		= 32
64};
65
66struct 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
90tcu::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::UNSIGNED_INT_24_8);
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
103tcu::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_INT_24_8);
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
118class DepthStencilClearCase : public TestCase
119{
120public:
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
129private:
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
145DepthStencilClearCase::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
158DepthStencilClearCase::~DepthStencilClearCase (void)
159{
160	DepthStencilClearCase::deinit();
161}
162
163void 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
193void DepthStencilClearCase::deinit (void)
194{
195	delete m_visProgram;
196	m_visProgram = DE_NULL;
197}
198
199DepthStencilClearCase::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
227void 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
276void 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 / 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*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
397void 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.setPixel(Vec4(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.getPixel(x, 0).x();
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.getPixelUint(x, 0).w();
477					deUint32	newVal	= ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask;
478					rowAccess.setPixel(tcu::UVec4(newVal), x, 0);
479				}
480			}
481
482			// Map to colors.
483			for (int x = 0; x < dst.getWidth(); x++)
484			{
485				deUint32	stencil		= rowAccess.getPixelUint(x, 0).w();
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
496DepthStencilClearTests::DepthStencilClearTests (Context& context)
497	: TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
498{
499}
500
501void 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