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 Shadow texture lookup tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fTextureShadowTests.hpp"
25#include "gluTexture.hpp"
26#include "gluPixelTransfer.hpp"
27#include "gluTextureUtil.hpp"
28#include "glsTextureTestUtil.hpp"
29#include "tcuTextureUtil.hpp"
30#include "tcuRenderTarget.hpp"
31#include "tcuTexCompareVerifier.hpp"
32#include "deString.h"
33#include "deMath.h"
34#include "deStringUtil.hpp"
35#include "glwFunctions.hpp"
36#include "glwEnums.hpp"
37
38namespace deqp
39{
40namespace gles3
41{
42namespace Functional
43{
44
45using std::vector;
46using std::string;
47using tcu::TestLog;
48using namespace deqp::gls::TextureTestUtil;
49using namespace glu::TextureTestUtil;
50
51enum
52{
53	TEX2D_VIEWPORT_WIDTH		= 64,
54	TEX2D_VIEWPORT_HEIGHT		= 64,
55	TEX2D_MIN_VIEWPORT_WIDTH	= 64,
56	TEX2D_MIN_VIEWPORT_HEIGHT	= 64
57};
58
59static bool isFloatingPointDepthFormat (const tcu::TextureFormat& format)
60{
61	// Only two depth and depth-stencil formats are floating point
62	return	(format.order == tcu::TextureFormat::D && format.type == tcu::TextureFormat::FLOAT) ||
63			(format.order == tcu::TextureFormat::DS && format.type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV);
64}
65
66static void clampFloatingPointTexture (const tcu::PixelBufferAccess& access)
67{
68	DE_ASSERT(isFloatingPointDepthFormat(access.getFormat()));
69
70	for (int z = 0; z < access.getDepth(); ++z)
71	for (int y = 0; y < access.getHeight(); ++y)
72	for (int x = 0; x < access.getWidth(); ++x)
73		access.setPixDepth( de::clamp(access.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
74}
75
76static void clampFloatingPointTexture (tcu::Texture2D& target)
77{
78	for (int level = 0; level < target.getNumLevels(); ++level)
79		if (!target.isLevelEmpty(level))
80			clampFloatingPointTexture(target.getLevel(level));
81}
82
83static void clampFloatingPointTexture (tcu::Texture2DArray& target)
84{
85	for (int level = 0; level < target.getNumLevels(); ++level)
86		if (!target.isLevelEmpty(level))
87			clampFloatingPointTexture(target.getLevel(level));
88}
89
90static void clampFloatingPointTexture (tcu::TextureCube& target)
91{
92	for (int level = 0; level < target.getNumLevels(); ++level)
93		for (int face = tcu::CUBEFACE_NEGATIVE_X; face < tcu::CUBEFACE_LAST; ++face)
94			clampFloatingPointTexture(target.getLevelFace(level, (tcu::CubeFace)face));
95}
96
97template<typename TextureType>
98bool verifyTexCompareResult (tcu::TestContext&						testCtx,
99							 const tcu::ConstPixelBufferAccess&		result,
100							 const TextureType&						src,
101							 const float*							texCoord,
102							 const ReferenceParams&					sampleParams,
103							 const tcu::TexComparePrecision&		comparePrec,
104							 const tcu::LodPrecision&				lodPrec,
105							 const tcu::PixelFormat&				pixelFormat)
106{
107	tcu::TestLog&	log					= testCtx.getLog();
108	tcu::Surface	reference			(result.getWidth(), result.getHeight());
109	tcu::Surface	errorMask			(result.getWidth(), result.getHeight());
110	const tcu::Vec3	nonShadowThreshold	= tcu::computeFixedPointThreshold(getBitsVec(pixelFormat)-1).swizzle(1,2,3);
111	int				numFailedPixels;
112
113	// sampleTexture() expects source image to be the same state as it would be in a GL implementation, that is
114	// the floating point depth values should be in [0, 1] range as data is clamped during texture upload. Since
115	// we don't have a separate "uploading" phase and just reuse the buffer we used for GL-upload, do the clamping
116	// here if necessary.
117
118	if (isFloatingPointDepthFormat(src.getFormat()))
119	{
120		TextureType clampedSource(src);
121
122		clampFloatingPointTexture(clampedSource);
123
124		// sample clamped values
125
126		sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), clampedSource, texCoord, sampleParams);
127		numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), clampedSource, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
128	}
129	else
130	{
131		// sample raw values (they are guaranteed to be in [0, 1] range as the format cannot represent any other values)
132
133		sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
134		numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
135	}
136
137	if (numFailedPixels > 0)
138		log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
139
140	log << TestLog::ImageSet("VerifyResult", "Verification result")
141		<< TestLog::Image("Rendered", "Rendered image", result);
142
143	if (numFailedPixels > 0)
144	{
145		log << TestLog::Image("Reference", "Ideal reference image", reference)
146			<< TestLog::Image("ErrorMask", "Error mask", errorMask);
147	}
148
149	log << TestLog::EndImageSet;
150
151	return numFailedPixels == 0;
152}
153
154class Texture2DShadowCase : public TestCase
155{
156public:
157									Texture2DShadowCase			(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc);
158									~Texture2DShadowCase		(void);
159
160	void							init						(void);
161	void							deinit						(void);
162	IterateResult					iterate						(void);
163
164private:
165									Texture2DShadowCase			(const Texture2DShadowCase& other);
166	Texture2DShadowCase&			operator=					(const Texture2DShadowCase& other);
167
168	const deUint32					m_minFilter;
169	const deUint32					m_magFilter;
170	const deUint32					m_wrapS;
171	const deUint32					m_wrapT;
172	const deUint32					m_format;
173	const int						m_width;
174	const int						m_height;
175	const deUint32					m_compareFunc;
176
177	struct FilterCase
178	{
179		const glu::Texture2D*	texture;
180		tcu::Vec2				minCoord;
181		tcu::Vec2				maxCoord;
182		float					ref;
183
184		FilterCase (void)
185			: texture	(DE_NULL)
186			, ref		(0.0f)
187		{
188		}
189
190		FilterCase (const glu::Texture2D* tex_, const float ref_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
191			: texture	(tex_)
192			, minCoord	(minCoord_)
193			, maxCoord	(maxCoord_)
194			, ref		(ref_)
195		{
196		}
197	};
198
199	std::vector<glu::Texture2D*>	m_textures;
200	std::vector<FilterCase>			m_cases;
201
202	TextureRenderer					m_renderer;
203
204	int								m_caseNdx;
205};
206
207Texture2DShadowCase::Texture2DShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc)
208	: TestCase			(context, name, desc)
209	, m_minFilter		(minFilter)
210	, m_magFilter		(magFilter)
211	, m_wrapS			(wrapS)
212	, m_wrapT			(wrapT)
213	, m_format			(format)
214	, m_width			(width)
215	, m_height			(height)
216	, m_compareFunc		(compareFunc)
217	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
218	, m_caseNdx			(0)
219{
220}
221
222Texture2DShadowCase::~Texture2DShadowCase (void)
223{
224	deinit();
225}
226
227void Texture2DShadowCase::init (void)
228{
229	try
230	{
231		// Create 2 textures.
232		m_textures.reserve(2);
233		m_textures.push_back(new glu::Texture2D(m_context.getRenderContext(), m_format, m_width, m_height));
234		m_textures.push_back(new glu::Texture2D(m_context.getRenderContext(), m_format, m_width, m_height));
235
236		int numLevels = m_textures[0]->getRefTexture().getNumLevels();
237
238		// Fill first gradient texture.
239		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
240		{
241			m_textures[0]->getRefTexture().allocLevel(levelNdx);
242			tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
243		}
244
245		// Fill second with grid texture.
246		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
247		{
248			deUint32	step	= 0x00ffffff / numLevels;
249			deUint32	rgb		= step*levelNdx;
250			deUint32	colorA	= 0xff000000 | rgb;
251			deUint32	colorB	= 0xff000000 | ~rgb;
252
253			m_textures[1]->getRefTexture().allocLevel(levelNdx);
254			tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec(), tcu::RGBA(colorB).toVec());
255		}
256
257		// Upload.
258		for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
259			(*i)->upload();
260	}
261	catch (const std::exception&)
262	{
263		// Clean up to save memory.
264		Texture2DShadowCase::deinit();
265		throw;
266	}
267
268	// Compute cases.
269	{
270		const float refInRangeUpper		= (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
271		const float refInRangeLower		= (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
272		const float refOutOfBoundsUpper	= 1.1f;		// !< lookup function should clamp values to [0, 1] range
273		const float refOutOfBoundsLower	= -0.1f;
274
275		const struct
276		{
277			int		texNdx;
278			float	ref;
279			float	lodX;
280			float	lodY;
281			float	oX;
282			float	oY;
283		} cases[] =
284		{
285			{ 0,	refInRangeUpper,		1.6f,	2.9f,	-1.0f,	-2.7f	},
286			{ 0,	refInRangeLower,		-2.0f,	-1.35f,	-0.2f,	0.7f	},
287			{ 1,	refInRangeUpper,		0.14f,	0.275f,	-1.5f,	-1.1f	},
288			{ 1,	refInRangeLower,		-0.92f,	-2.64f,	0.4f,	-0.1f	},
289			{ 1,	refOutOfBoundsUpper,	-0.39f,	-0.52f,	0.65f,	0.87f	},
290			{ 1,	refOutOfBoundsLower,	-1.55f,	0.65f,	0.35f,	0.91f	},
291		};
292
293		const float	viewportW	= (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_context.getRenderTarget().getWidth());
294		const float	viewportH	= (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_context.getRenderTarget().getHeight());
295
296		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
297		{
298			const int	texNdx	= de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
299			const float ref		= cases[caseNdx].ref;
300			const float	lodX	= cases[caseNdx].lodX;
301			const float	lodY	= cases[caseNdx].lodY;
302			const float	oX		= cases[caseNdx].oX;
303			const float	oY		= cases[caseNdx].oY;
304			const float	sX		= deFloatExp2(lodX)*viewportW / float(m_textures[texNdx]->getRefTexture().getWidth());
305			const float	sY		= deFloatExp2(lodY)*viewportH / float(m_textures[texNdx]->getRefTexture().getHeight());
306
307			m_cases.push_back(FilterCase(m_textures[texNdx], ref, tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
308		}
309	}
310
311	m_caseNdx = 0;
312	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
313}
314
315void Texture2DShadowCase::deinit (void)
316{
317	for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
318		delete *i;
319	m_textures.clear();
320
321	m_renderer.clear();
322	m_cases.clear();
323}
324
325Texture2DShadowCase::IterateResult Texture2DShadowCase::iterate (void)
326{
327	const glw::Functions&			gl				= m_context.getRenderContext().getFunctions();
328	const RandomViewport			viewport		(m_context.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
329	const FilterCase&				curCase			= m_cases[m_caseNdx];
330	const tcu::ScopedLogSection		section			(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
331	ReferenceParams					sampleParams	(TEXTURETYPE_2D);
332	tcu::Surface					rendered		(viewport.width, viewport.height);
333	vector<float>					texCoord;
334
335	if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
336		throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
337
338	// Setup params for reference.
339	sampleParams.sampler			= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
340	sampleParams.sampler.compare	= glu::mapGLCompareFunc(m_compareFunc);
341	sampleParams.samplerType		= SAMPLERTYPE_SHADOW;
342	sampleParams.lodMode			= LODMODE_EXACT;
343	sampleParams.ref				= curCase.ref;
344
345	m_testCtx.getLog() << TestLog::Message << "Compare reference value =  " << sampleParams.ref << TestLog::EndMessage;
346
347	// Compute texture coordinates.
348	m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
349	computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
350
351	gl.bindTexture	(GL_TEXTURE_2D, curCase.texture->getGLTexture());
352	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,		m_minFilter);
353	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,		m_magFilter);
354	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,			m_wrapS);
355	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,			m_wrapT);
356	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,	GL_COMPARE_REF_TO_TEXTURE);
357	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC,	m_compareFunc);
358
359	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
360	m_renderer.renderQuad(0, &texCoord[0], sampleParams);
361	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
362
363	{
364		const tcu::PixelFormat		pixelFormat		= m_context.getRenderTarget().getPixelFormat();
365		tcu::LodPrecision			lodPrecision;
366		tcu::TexComparePrecision	texComparePrecision;
367
368		lodPrecision.derivateBits			= 18;
369		lodPrecision.lodBits				= 6;
370		texComparePrecision.coordBits		= tcu::IVec3(20,20,0);
371		texComparePrecision.uvwBits			= tcu::IVec3(7,7,0);
372		texComparePrecision.pcfBits			= 5;
373		texComparePrecision.referenceBits	= 16;
374		texComparePrecision.resultBits		= pixelFormat.redBits-1;
375
376		const bool isHighQuality = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
377														  &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
378
379		if (!isHighQuality)
380		{
381			m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
382
383			lodPrecision.lodBits			= 4;
384			texComparePrecision.uvwBits		= tcu::IVec3(4,4,0);
385			texComparePrecision.pcfBits		= 0;
386
387			const bool isOk = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
388													 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
389
390			if (!isOk)
391			{
392				m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
393				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
394			}
395			else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
396				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
397		}
398	}
399
400	m_caseNdx += 1;
401	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
402}
403
404class TextureCubeShadowCase : public TestCase
405{
406public:
407								TextureCubeShadowCase		(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc);
408								~TextureCubeShadowCase		(void);
409
410	void						init						(void);
411	void						deinit						(void);
412	IterateResult				iterate						(void);
413
414private:
415								TextureCubeShadowCase		(const TextureCubeShadowCase& other);
416	TextureCubeShadowCase&		operator=					(const TextureCubeShadowCase& other);
417
418	const deUint32				m_minFilter;
419	const deUint32				m_magFilter;
420	const deUint32				m_wrapS;
421	const deUint32				m_wrapT;
422
423	const deUint32				m_format;
424	const int					m_size;
425
426	const deUint32				m_compareFunc;
427
428	struct FilterCase
429	{
430		const glu::TextureCube*	texture;
431		tcu::Vec2				bottomLeft;
432		tcu::Vec2				topRight;
433		float					ref;
434
435		FilterCase (void)
436			: texture	(DE_NULL)
437			, ref		(0.0f)
438		{
439		}
440
441		FilterCase (const glu::TextureCube* tex_, const float ref_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
442			: texture	(tex_)
443			, bottomLeft(bottomLeft_)
444			, topRight	(topRight_)
445			, ref		(ref_)
446		{
447		}
448	};
449
450	glu::TextureCube*			m_gradientTex;
451	glu::TextureCube*			m_gridTex;
452	std::vector<FilterCase>		m_cases;
453
454	TextureRenderer				m_renderer;
455
456	int							m_caseNdx;
457};
458
459TextureCubeShadowCase::TextureCubeShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc)
460	: TestCase			(context, name, desc)
461	, m_minFilter		(minFilter)
462	, m_magFilter		(magFilter)
463	, m_wrapS			(wrapS)
464	, m_wrapT			(wrapT)
465	, m_format			(format)
466	, m_size			(size)
467	, m_compareFunc		(compareFunc)
468	, m_gradientTex		(DE_NULL)
469	, m_gridTex			(DE_NULL)
470	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
471	, m_caseNdx			(0)
472{
473}
474
475TextureCubeShadowCase::~TextureCubeShadowCase (void)
476{
477	TextureCubeShadowCase::deinit();
478}
479
480void TextureCubeShadowCase::init (void)
481{
482	try
483	{
484		DE_ASSERT(!m_gradientTex && !m_gridTex);
485
486		int						numLevels	= deLog2Floor32(m_size)+1;
487		tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(m_format);
488		tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
489		tcu::Vec4				cBias		= fmtInfo.valueMin;
490		tcu::Vec4				cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
491
492		// Create textures.
493		m_gradientTex	= new glu::TextureCube(m_context.getRenderContext(), m_format, m_size);
494		m_gridTex		= new glu::TextureCube(m_context.getRenderContext(), m_format, m_size);
495
496		// Fill first with gradient texture.
497		static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
498		{
499			{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
500			{ tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
501			{ tcu::Vec4(-1.0f,  0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
502			{ tcu::Vec4(-1.0f, -1.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
503			{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
504			{ tcu::Vec4( 0.0f,  0.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
505		};
506		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
507		{
508			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
509			{
510				m_gradientTex->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
511				tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
512			}
513		}
514
515		// Fill second with grid texture.
516		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
517		{
518			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
519			{
520				deUint32	step	= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
521				deUint32	rgb		= step*levelNdx*face;
522				deUint32	colorA	= 0xff000000 | rgb;
523				deUint32	colorB	= 0xff000000 | ~rgb;
524
525				m_gridTex->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
526				tcu::fillWithGrid(m_gridTex->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
527			}
528		}
529
530		// Upload.
531		m_gradientTex->upload();
532		m_gridTex->upload();
533	}
534	catch (const std::exception&)
535	{
536		// Clean up to save memory.
537		TextureCubeShadowCase::deinit();
538		throw;
539	}
540
541	// Compute cases
542	{
543		const float refInRangeUpper		= (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
544		const float refInRangeLower		= (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
545		const float refOutOfBoundsUpper	= 1.1f;
546		const float refOutOfBoundsLower	= -0.1f;
547		const bool	singleSample		= m_context.getRenderTarget().getNumSamples() == 0;
548
549		if (singleSample)
550			m_cases.push_back(FilterCase(m_gradientTex,	refInRangeUpper, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f)));	// minification
551		else
552			m_cases.push_back(FilterCase(m_gradientTex,	refInRangeUpper, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));	// minification - w/ tuned coordinates to avoid hitting triangle edges
553
554		m_cases.push_back(FilterCase(m_gradientTex,	refInRangeLower,		tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f)));	// magnification
555		m_cases.push_back(FilterCase(m_gridTex,		refInRangeUpper,		tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));	// minification
556		m_cases.push_back(FilterCase(m_gridTex,		refInRangeLower,		tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f)));	// magnification
557		m_cases.push_back(FilterCase(m_gridTex,		refOutOfBoundsUpper,	tcu::Vec2(-0.61f, -0.1f), tcu::Vec2(0.9f, 1.18f)));	// reference value clamp, upper
558
559		if (singleSample)
560			m_cases.push_back(FilterCase(m_gridTex,	refOutOfBoundsLower, tcu::Vec2(-0.75f, 1.0f), tcu::Vec2(0.05f, 0.75f)));	// reference value clamp, lower
561		else
562			m_cases.push_back(FilterCase(m_gridTex,	refOutOfBoundsLower, tcu::Vec2(-0.75f, 1.0f), tcu::Vec2(0.25f, 0.75f)));	// reference value clamp, lower
563	}
564
565	m_caseNdx = 0;
566	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
567}
568
569void TextureCubeShadowCase::deinit (void)
570{
571	delete m_gradientTex;
572	delete m_gridTex;
573
574	m_gradientTex	= DE_NULL;
575	m_gridTex		= DE_NULL;
576
577	m_renderer.clear();
578	m_cases.clear();
579}
580
581static const char* getFaceDesc (const tcu::CubeFace face)
582{
583	switch (face)
584	{
585		case tcu::CUBEFACE_NEGATIVE_X:	return "-X";
586		case tcu::CUBEFACE_POSITIVE_X:	return "+X";
587		case tcu::CUBEFACE_NEGATIVE_Y:	return "-Y";
588		case tcu::CUBEFACE_POSITIVE_Y:	return "+Y";
589		case tcu::CUBEFACE_NEGATIVE_Z:	return "-Z";
590		case tcu::CUBEFACE_POSITIVE_Z:	return "+Z";
591		default:
592			DE_ASSERT(false);
593			return DE_NULL;
594	}
595}
596
597TextureCubeShadowCase::IterateResult TextureCubeShadowCase::iterate (void)
598{
599	const glw::Functions&			gl				= m_context.getRenderContext().getFunctions();
600	const int						viewportSize	= 28;
601	const RandomViewport			viewport		(m_context.getRenderTarget(), viewportSize, viewportSize, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
602	const tcu::ScopedLogSection		iterSection		(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
603	const FilterCase&				curCase			= m_cases[m_caseNdx];
604	ReferenceParams					sampleParams	(TEXTURETYPE_CUBE);
605
606	if (viewport.width < viewportSize || viewport.height < viewportSize)
607		throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__);
608
609	// Setup texture
610	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture());
611	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
612	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
613	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
614	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
615	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE,	GL_COMPARE_REF_TO_TEXTURE);
616	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC,	m_compareFunc);
617
618	// Other state
619	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
620
621	// Params for reference computation.
622	sampleParams.sampler					= glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
623	sampleParams.sampler.seamlessCubeMap	= true;
624	sampleParams.sampler.compare			= glu::mapGLCompareFunc(m_compareFunc);
625	sampleParams.samplerType				= SAMPLERTYPE_SHADOW;
626	sampleParams.lodMode					= LODMODE_EXACT;
627	sampleParams.ref						= curCase.ref;
628
629	m_testCtx.getLog()
630		<< TestLog::Message
631		<< "Compare reference value =  " << sampleParams.ref << "\n"
632		<< "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight
633		<< TestLog::EndMessage;
634
635	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
636	{
637		const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
638		tcu::Surface			result		(viewport.width, viewport.height);
639		vector<float>			texCoord;
640
641		computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
642
643		m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
644
645		// \todo Log texture coordinates.
646
647		m_renderer.renderQuad(0, &texCoord[0], sampleParams);
648		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
649
650		glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, result.getAccess());
651		GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
652
653		{
654			const tcu::PixelFormat		pixelFormat		= m_context.getRenderTarget().getPixelFormat();
655			tcu::LodPrecision			lodPrecision;
656			tcu::TexComparePrecision	texComparePrecision;
657
658			lodPrecision.derivateBits			= 10;
659			lodPrecision.lodBits				= 5;
660			texComparePrecision.coordBits		= tcu::IVec3(10,10,10);
661			texComparePrecision.uvwBits			= tcu::IVec3(6,6,0);
662			texComparePrecision.pcfBits			= 5;
663			texComparePrecision.referenceBits	= 16;
664			texComparePrecision.resultBits		= pixelFormat.redBits-1;
665
666			const bool isHighQuality = verifyTexCompareResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
667															  &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
668
669			if (!isHighQuality)
670			{
671				m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
672
673				lodPrecision.lodBits			= 4;
674				texComparePrecision.uvwBits		= tcu::IVec3(4,4,0);
675				texComparePrecision.pcfBits		= 0;
676
677				const bool isOk = verifyTexCompareResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
678														 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
679
680				if (!isOk)
681				{
682					m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
683					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
684				}
685				else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
686					m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
687			}
688		}
689	}
690
691	m_caseNdx += 1;
692	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
693}
694
695class Texture2DArrayShadowCase : public TestCase
696{
697public:
698								Texture2DArrayShadowCase	(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc);
699								~Texture2DArrayShadowCase	(void);
700
701	void						init						(void);
702	void						deinit						(void);
703	IterateResult				iterate						(void);
704
705private:
706								Texture2DArrayShadowCase	(const Texture2DArrayShadowCase& other);
707	Texture2DArrayShadowCase&	operator=					(const Texture2DArrayShadowCase& other);
708
709	const deUint32				m_minFilter;
710	const deUint32				m_magFilter;
711	const deUint32				m_wrapS;
712	const deUint32				m_wrapT;
713
714	const deUint32				m_format;
715	const int					m_width;
716	const int					m_height;
717	const int					m_numLayers;
718
719	const deUint32				m_compareFunc;
720
721	struct FilterCase
722	{
723		const glu::Texture2DArray*	texture;
724		tcu::Vec3					minCoord;
725		tcu::Vec3					maxCoord;
726		float						ref;
727
728		FilterCase (void)
729			: texture	(DE_NULL)
730			, ref		(0.0f)
731		{
732		}
733
734		FilterCase (const glu::Texture2DArray* tex_, float ref_, const tcu::Vec3& minCoord_, const tcu::Vec3& maxCoord_)
735			: texture	(tex_)
736			, minCoord	(minCoord_)
737			, maxCoord	(maxCoord_)
738			, ref		(ref_)
739		{
740		}
741	};
742
743	glu::Texture2DArray*		m_gradientTex;
744	glu::Texture2DArray*		m_gridTex;
745	std::vector<FilterCase>		m_cases;
746
747	TextureRenderer				m_renderer;
748
749	int							m_caseNdx;
750};
751
752Texture2DArrayShadowCase::Texture2DArrayShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc)
753	: TestCase			(context, name, desc)
754	, m_minFilter		(minFilter)
755	, m_magFilter		(magFilter)
756	, m_wrapS			(wrapS)
757	, m_wrapT			(wrapT)
758	, m_format			(format)
759	, m_width			(width)
760	, m_height			(height)
761	, m_numLayers		(numLayers)
762	, m_compareFunc		(compareFunc)
763	, m_gradientTex		(DE_NULL)
764	, m_gridTex			(DE_NULL)
765	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
766	, m_caseNdx			(0)
767{
768}
769
770Texture2DArrayShadowCase::~Texture2DArrayShadowCase (void)
771{
772	Texture2DArrayShadowCase::deinit();
773}
774
775void Texture2DArrayShadowCase::init (void)
776{
777	try
778	{
779		tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(m_format);
780		tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
781		tcu::Vec4				cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
782		tcu::Vec4				cBias		= fmtInfo.valueMin;
783		int						numLevels	= deLog2Floor32(de::max(m_width, m_height)) + 1;
784
785		// Create textures.
786		m_gradientTex	= new glu::Texture2DArray(m_context.getRenderContext(), m_format, m_width, m_height, m_numLayers);
787		m_gridTex		= new glu::Texture2DArray(m_context.getRenderContext(), m_format, m_width, m_height, m_numLayers);
788
789		// Fill first gradient texture.
790		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
791		{
792			tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
793			tcu::Vec4 gMax = tcu::Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
794
795			m_gradientTex->getRefTexture().allocLevel(levelNdx);
796			tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
797		}
798
799		// Fill second with grid texture.
800		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
801		{
802			deUint32	step	= 0x00ffffff / numLevels;
803			deUint32	rgb		= step*levelNdx;
804			deUint32	colorA	= 0xff000000 | rgb;
805			deUint32	colorB	= 0xff000000 | ~rgb;
806
807			m_gridTex->getRefTexture().allocLevel(levelNdx);
808			tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
809		}
810
811		// Upload.
812		m_gradientTex->upload();
813		m_gridTex->upload();
814	}
815	catch (...)
816	{
817		// Clean up to save memory.
818		Texture2DArrayShadowCase::deinit();
819		throw;
820	}
821
822	// Compute cases.
823	{
824		const float refInRangeUpper		= (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
825		const float refInRangeLower		= (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
826		const float refOutOfBoundsUpper	= 1.1f;		// !< lookup function should clamp values to [0, 1] range
827		const float refOutOfBoundsLower	= -0.1f;
828
829		const struct
830		{
831			int		texNdx;
832			float	ref;
833			float	lodX;
834			float	lodY;
835			float	oX;
836			float	oY;
837		} cases[] =
838		{
839			{ 0,	refInRangeUpper,		1.6f,	2.9f,	-1.0f,	-2.7f	},
840			{ 0,	refInRangeLower,		-2.0f,	-1.35f,	-0.2f,	0.7f	},
841			{ 1,	refInRangeUpper,		0.14f,	0.275f,	-1.5f,	-1.1f	},
842			{ 1,	refInRangeLower,		-0.92f,	-2.64f,	0.4f,	-0.1f	},
843			{ 1,	refOutOfBoundsUpper,	-0.49f,	-0.22f,	0.45f,	0.97f	},
844			{ 1,	refOutOfBoundsLower,	-0.85f,	0.75f,	0.25f,	0.61f	},
845		};
846
847		const float	viewportW	= (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_context.getRenderTarget().getWidth());
848		const float	viewportH	= (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_context.getRenderTarget().getHeight());
849
850		const float	minLayer	= -0.5f;
851		const float	maxLayer	= (float)m_numLayers;
852
853		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
854		{
855			const glu::Texture2DArray*	tex		= cases[caseNdx].texNdx > 0 ? m_gridTex : m_gradientTex;
856			const float					ref		= cases[caseNdx].ref;
857			const float					lodX	= cases[caseNdx].lodX;
858			const float					lodY	= cases[caseNdx].lodY;
859			const float					oX		= cases[caseNdx].oX;
860			const float					oY		= cases[caseNdx].oY;
861			const float					sX		= deFloatExp2(lodX)*viewportW / float(tex->getRefTexture().getWidth());
862			const float					sY		= deFloatExp2(lodY)*viewportH / float(tex->getRefTexture().getHeight());
863
864			m_cases.push_back(FilterCase(tex, ref, tcu::Vec3(oX, oY, minLayer), tcu::Vec3(oX+sX, oY+sY, maxLayer)));
865		}
866	}
867
868	m_caseNdx = 0;
869	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
870}
871
872void Texture2DArrayShadowCase::deinit (void)
873{
874	delete m_gradientTex;
875	delete m_gridTex;
876
877	m_gradientTex	= DE_NULL;
878	m_gridTex		= DE_NULL;
879
880	m_renderer.clear();
881	m_cases.clear();
882}
883
884Texture2DArrayShadowCase::IterateResult Texture2DArrayShadowCase::iterate (void)
885{
886	const glw::Functions&			gl				= m_context.getRenderContext().getFunctions();
887	const RandomViewport			viewport		(m_context.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
888	const FilterCase&				curCase			= m_cases[m_caseNdx];
889	const tcu::ScopedLogSection		section			(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
890	ReferenceParams					sampleParams	(TEXTURETYPE_2D_ARRAY);
891	tcu::Surface					rendered		(viewport.width, viewport.height);
892
893	const float						texCoord[]		=
894	{
895		curCase.minCoord.x(), curCase.minCoord.y(), curCase.minCoord.z(),
896		curCase.minCoord.x(), curCase.maxCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
897		curCase.maxCoord.x(), curCase.minCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
898		curCase.maxCoord.x(), curCase.maxCoord.y(), curCase.maxCoord.z()
899	};
900
901	if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
902		throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
903
904	// Setup params for reference.
905	sampleParams.sampler			= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
906	sampleParams.sampler.compare	= glu::mapGLCompareFunc(m_compareFunc);
907	sampleParams.samplerType		= SAMPLERTYPE_SHADOW;
908	sampleParams.lodMode			= LODMODE_EXACT;
909	sampleParams.ref				= curCase.ref;
910
911	m_testCtx.getLog()
912		<< TestLog::Message
913		<< "Compare reference value =  " << sampleParams.ref << "\n"
914		<< "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord
915		<< TestLog::EndMessage;
916
917	gl.bindTexture	(GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture());
918	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,	m_minFilter);
919	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,	m_magFilter);
920	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,		m_wrapS);
921	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,		m_wrapT);
922	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE,	GL_COMPARE_REF_TO_TEXTURE);
923	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC,	m_compareFunc);
924
925	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
926	m_renderer.renderQuad(0, &texCoord[0], sampleParams);
927	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
928
929	{
930		const tcu::PixelFormat		pixelFormat		= m_context.getRenderTarget().getPixelFormat();
931		tcu::LodPrecision			lodPrecision;
932		tcu::TexComparePrecision	texComparePrecision;
933
934		lodPrecision.derivateBits			= 18;
935		lodPrecision.lodBits				= 6;
936		texComparePrecision.coordBits		= tcu::IVec3(20,20,20);
937		texComparePrecision.uvwBits			= tcu::IVec3(7,7,7);
938		texComparePrecision.pcfBits			= 5;
939		texComparePrecision.referenceBits	= 16;
940		texComparePrecision.resultBits		= pixelFormat.redBits-1;
941
942		const bool isHighQuality = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
943														  &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
944
945		if (!isHighQuality)
946		{
947			m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
948
949			lodPrecision.lodBits			= 4;
950			texComparePrecision.uvwBits		= tcu::IVec3(4,4,4);
951			texComparePrecision.pcfBits		= 0;
952
953			const bool isOk = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
954													 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
955
956			if (!isOk)
957			{
958				m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
959				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
960			}
961			else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
962				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
963		}
964	}
965
966	m_caseNdx += 1;
967	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
968}
969
970TextureShadowTests::TextureShadowTests (Context& context)
971	: TestCaseGroup(context, "shadow", "Shadow texture lookup tests")
972{
973}
974
975TextureShadowTests::~TextureShadowTests (void)
976{
977}
978
979void TextureShadowTests::init (void)
980{
981	static const struct
982	{
983		const char*		name;
984		deUint32		format;
985	} formats[] =
986	{
987		{ "depth_component16",	GL_DEPTH_COMPONENT16	},
988		{ "depth_component32f",	GL_DEPTH_COMPONENT32F	},
989		{ "depth24_stencil8",	GL_DEPTH24_STENCIL8		}
990	};
991
992	static const struct
993	{
994		const char*		name;
995		deUint32		minFilter;
996		deUint32		magFilter;
997	} filters[] =
998	{
999		{ "nearest",				GL_NEAREST,					GL_NEAREST	},
1000		{ "linear",					GL_LINEAR,					GL_LINEAR	},
1001		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST,	GL_LINEAR	},
1002		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST,	GL_LINEAR	},
1003		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR,	GL_LINEAR	},
1004		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR,	GL_LINEAR	}
1005	};
1006
1007	static const struct
1008	{
1009		const char*		name;
1010		deUint32		func;
1011	} compareFuncs[] =
1012	{
1013		{ "less_or_equal",		GL_LEQUAL	},
1014		{ "greater_or_equal",	GL_GEQUAL	},
1015		{ "less",				GL_LESS		},
1016		{ "greater",			GL_GREATER	},
1017		{ "equal",				GL_EQUAL	},
1018		{ "not_equal",			GL_NOTEQUAL	},
1019		{ "always",				GL_ALWAYS	},
1020		{ "never",				GL_NEVER	}
1021	};
1022
1023	// 2D cases.
1024	{
1025		tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D texture shadow lookup tests");
1026		addChild(group2D);
1027
1028		for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1029		{
1030			tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1031			group2D->addChild(filterGroup);
1032
1033			for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1034			{
1035				for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1036				{
1037					deUint32		minFilter		= filters[filterNdx].minFilter;
1038					deUint32		magFilter		= filters[filterNdx].magFilter;
1039					deUint32		format			= formats[formatNdx].format;
1040					deUint32		compareFunc		= compareFuncs[compareNdx].func;
1041					const deUint32	wrapS			= GL_REPEAT;
1042					const deUint32	wrapT			= GL_REPEAT;
1043					const int		width			= 32;
1044					const int		height			= 64;
1045					string			name			= string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1046
1047					filterGroup->addChild(new Texture2DShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, compareFunc));
1048				}
1049			}
1050		}
1051	}
1052
1053	// Cubemap cases.
1054	{
1055		tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube map texture shadow lookup tests");
1056		addChild(groupCube);
1057
1058		for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1059		{
1060			tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1061			groupCube->addChild(filterGroup);
1062
1063			for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1064			{
1065				for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1066				{
1067					deUint32		minFilter		= filters[filterNdx].minFilter;
1068					deUint32		magFilter		= filters[filterNdx].magFilter;
1069					deUint32		format			= formats[formatNdx].format;
1070					deUint32		compareFunc		= compareFuncs[compareNdx].func;
1071					const deUint32	wrapS			= GL_REPEAT;
1072					const deUint32	wrapT			= GL_REPEAT;
1073					const int		size			= 32;
1074					string			name			= string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1075
1076					filterGroup->addChild(new TextureCubeShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, size, compareFunc));
1077				}
1078			}
1079		}
1080	}
1081
1082	// 2D array cases.
1083	{
1084		tcu::TestCaseGroup* group2DArray = new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D texture array shadow lookup tests");
1085		addChild(group2DArray);
1086
1087		for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1088		{
1089			tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1090			group2DArray->addChild(filterGroup);
1091
1092			for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1093			{
1094				for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1095				{
1096					deUint32		minFilter		= filters[filterNdx].minFilter;
1097					deUint32		magFilter		= filters[filterNdx].magFilter;
1098					deUint32		format			= formats[formatNdx].format;
1099					deUint32		compareFunc		= compareFuncs[compareNdx].func;
1100					const deUint32	wrapS			= GL_REPEAT;
1101					const deUint32	wrapT			= GL_REPEAT;
1102					const int		width			= 32;
1103					const int		height			= 64;
1104					const int		numLayers		= 8;
1105					string			name			= string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1106
1107					filterGroup->addChild(new Texture2DArrayShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, numLayers, compareFunc));
1108				}
1109			}
1110		}
1111	}
1112}
1113
1114} // Functional
1115} // gles3
1116} // deqp
1117