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
44namespace deqp
45{
46namespace gles3
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::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
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_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
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			"#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
196void DepthStencilClearCase::deinit (void)
197{
198	delete m_visProgram;
199	m_visProgram = DE_NULL;
200}
201
202DepthStencilClearCase::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
230void 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
279void 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
400void 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
499DepthStencilClearTests::DepthStencilClearTests (Context& context)
500	: TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
501{
502}
503
504void 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