1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Texture filtering tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "tcuVectorUtil.hpp"
27 #include "tcuTexVerifierUtil.hpp"
28 #include "vkImageUtil.hpp"
29 #include "vkMemUtil.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "vktTestGroupUtil.hpp"
36 #include "vktTextureFilteringTests.hpp"
37 #include "vktTextureTestUtil.hpp"
38 #include <string>
39 #include <vector>
40 
41 using namespace vk;
42 
43 namespace vkt
44 {
45 namespace texture
46 {
47 
48 namespace
49 {
50 
51 using std::vector;
52 using std::string;
53 using tcu::TestLog;
54 using tcu::Sampler;
55 
56 using namespace texture::util;
57 using namespace glu::TextureTestUtil;
58 
59 enum
60 {
61 	TEXCUBE_VIEWPORT_SIZE		= 28,
62 
63 	TEX2D_VIEWPORT_WIDTH		= 64,
64 	TEX2D_VIEWPORT_HEIGHT		= 64,
65 
66 	TEX3D_VIEWPORT_WIDTH		= 64,
67 	TEX3D_VIEWPORT_HEIGHT		= 64,
68 };
69 
70 class Texture2DFilteringTestInstance : public TestInstance
71 {
72 public:
73 	typedef Texture2DTestCaseParameters	ParameterType;
74 
75 										Texture2DFilteringTestInstance		(Context& context, const ParameterType& testParameters);
76 										~Texture2DFilteringTestInstance		(void);
77 
78 	virtual tcu::TestStatus				iterate								(void);
79 private:
80 										Texture2DFilteringTestInstance		(const Texture2DFilteringTestInstance& other);
81 	Texture2DFilteringTestInstance&		operator=							(const Texture2DFilteringTestInstance& other);
82 
83 	struct FilterCase
84 	{
85 		int						textureIndex;
86 
87 		tcu::Vec2				minCoord;
88 		tcu::Vec2				maxCoord;
89 
FilterCasevkt::texture::__anon640f863c0111::Texture2DFilteringTestInstance::FilterCase90 		FilterCase (void)
91 			: textureIndex(-1)
92 		{
93 		}
94 
FilterCasevkt::texture::__anon640f863c0111::Texture2DFilteringTestInstance::FilterCase95 		FilterCase (int tex_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
96 			: textureIndex	(tex_)
97 			, minCoord		(minCoord_)
98 			, maxCoord		(maxCoord_)
99 		{
100 		}
101 	};
102 
103 	const ParameterType			m_testParameters;
104 	vector<TestTexture2DSp>		m_textures;
105 	vector<FilterCase>			m_cases;
106 	TextureRenderer				m_renderer;
107 	int							m_caseNdx;
108 };
109 
Texture2DFilteringTestInstance(Context & context,const ParameterType & testParameters)110 Texture2DFilteringTestInstance::Texture2DFilteringTestInstance (Context& context, const ParameterType& testParameters)
111 	: TestInstance			(context)
112 	, m_testParameters		(testParameters)
113 	, m_renderer			(context, testParameters.sampleCount, TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT)
114 	, m_caseNdx				(0)
115 {
116 	const bool						mipmaps		= m_testParameters.mipmaps;
117 	const int						numLevels	= mipmaps ? deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height))+1 : 1;
118 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
119 	const tcu::Vec4					cBias		= fmtInfo.valueMin;
120 	const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
121 
122 	if ((testParameters.wrapS == Sampler::MIRRORED_ONCE ||
123 		testParameters.wrapT == Sampler::MIRRORED_ONCE) &&
124 		!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_sampler_mirror_clamp_to_edge"))
125 		TCU_THROW(NotSupportedError, "VK_KHR_sampler_mirror_clamp_to_edge not supported");
126 
127 	// Create 2 textures.
128 	m_textures.reserve(2);
129 	for (int ndx = 0; ndx < 2; ndx++)
130 		if (mipmaps)
131 			m_textures.push_back(TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height)));
132 		else
133 			m_textures.push_back(TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, 1)));
134 
135 	// Fill first gradient texture.
136 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
137 	{
138 		const tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
139 		const tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
140 
141 		tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, 0), gMin, gMax);
142 	}
143 
144 	// Fill second with grid texture.
145 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
146 	{
147 		const deUint32	step	= 0x00ffffff / numLevels;
148 		const deUint32	rgb		= step*levelNdx;
149 		const deUint32	colorA	= 0xff000000 | rgb;
150 		const deUint32	colorB	= 0xff000000 | ~rgb;
151 
152 		tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, 0), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
153 	}
154 
155 	// Upload.
156 	for (vector<TestTexture2DSp>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
157 	{
158 		m_renderer.add2DTexture(*i);
159 	}
160 
161 	// Compute cases.
162 	{
163 		const struct
164 		{
165 			const int		texNdx;
166 			const float		lodX;
167 			const float		lodY;
168 			const float		oX;
169 			const float		oY;
170 		} cases[] =
171 		{
172 			{ 0,	1.6f,	2.9f,	-1.0f,	-2.7f	},
173 			{ 0,	-2.0f,	-1.35f,	-0.2f,	0.7f	},
174 			{ 1,	0.14f,	0.275f,	-1.5f,	-1.1f	},
175 			{ 1,	-0.92f,	-2.64f,	0.4f,	-0.1f	},
176 		};
177 
178 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
179 		{
180 			const int	texNdx	= de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
181 			const float	lodX	= cases[caseNdx].lodX;
182 			const float	lodY	= cases[caseNdx].lodY;
183 			const float	oX		= cases[caseNdx].oX;
184 			const float	oY		= cases[caseNdx].oY;
185 			const float	sX		= deFloatExp2(lodX) * float(m_renderer.getRenderWidth()) / float(m_textures[texNdx]->getTexture().getWidth());
186 			const float	sY		= deFloatExp2(lodY) * float(m_renderer.getRenderHeight()) / float(m_textures[texNdx]->getTexture().getHeight());
187 
188 			m_cases.push_back(FilterCase(texNdx, tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
189 		}
190 	}
191 }
192 
~Texture2DFilteringTestInstance(void)193 Texture2DFilteringTestInstance::~Texture2DFilteringTestInstance (void)
194 {
195 }
196 
iterate(void)197 tcu::TestStatus Texture2DFilteringTestInstance::iterate (void)
198 {
199 	tcu::TestLog&					log			= m_context.getTestContext().getLog();
200 
201 	const pipeline::TestTexture2D&	texture		= m_renderer.get2DTexture(m_cases[m_caseNdx].textureIndex);
202 	const tcu::TextureFormat		texFmt		= texture.getTextureFormat();
203 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
204 	const FilterCase&				curCase		= m_cases[m_caseNdx];
205 	ReferenceParams					refParams	(TEXTURETYPE_2D);
206 	tcu::Surface					rendered	(m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
207 	vector<float>					texCoord;
208 
209 	// Setup params for reference.
210 
211 	refParams.sampler		= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter, !m_testParameters.unnormal);
212 	refParams.samplerType	= getSamplerType(texFmt);
213 	refParams.lodMode		= LODMODE_EXACT;
214 	refParams.colorBias		= fmtInfo.lookupBias;
215 	refParams.colorScale	= fmtInfo.lookupScale;
216 	refParams.unnormal		= m_testParameters.unnormal;
217 
218 	// Compute texture coordinates.
219 	log << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
220 	computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
221 
222 	m_renderer.renderQuad(rendered, curCase.textureIndex, &texCoord[0], refParams);
223 
224 	{
225 		const bool				isNearestOnly	= m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
226 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
227 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
228 		const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
229 		tcu::LodPrecision		lodPrecision;
230 		tcu::LookupPrecision	lookupPrecision;
231 
232 		lodPrecision.derivateBits		= 18;
233 		lodPrecision.lodBits			= 6;
234 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
235 		lookupPrecision.coordBits		= tcu::IVec3(20,20,0);
236 		lookupPrecision.uvwBits			= tcu::IVec3(7,7,0);
237 		lookupPrecision.colorMask		= getCompareMask(pixelFormat);
238 
239 		const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DView)texture.getTexture(),
240 													   &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
241 
242 		if (!isHighQuality)
243 		{
244 			// Evaluate against lower precision requirements.
245 			lodPrecision.lodBits	= 4;
246 			lookupPrecision.uvwBits	= tcu::IVec3(4,4,0);
247 
248 			log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
249 
250 			const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DView)texture.getTexture(),
251 												  &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
252 
253 			if (!isOk)
254 			{
255 				log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
256 				return tcu::TestStatus::fail("Image verification failed");
257 			}
258 		}
259 	}
260 
261 	m_caseNdx += 1;
262 	return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
263 }
264 
265 struct TextureCubeFilteringTestCaseParameters : public TextureCubeTestCaseParameters
266 {
267 	bool	onlySampleFaceInterior;
268 };
269 
270 class TextureCubeFilteringTestInstance : public TestInstance
271 {
272 public:
273 	typedef TextureCubeFilteringTestCaseParameters	ParameterType;
274 
275 													TextureCubeFilteringTestInstance	(Context& context, const ParameterType& testParameters);
276 													~TextureCubeFilteringTestInstance	(void);
277 
278 	virtual tcu::TestStatus							iterate								(void);
279 
280 private:
281 													TextureCubeFilteringTestInstance	(const TextureCubeFilteringTestInstance& other);
282 	TextureCubeFilteringTestInstance&				operator=							(const TextureCubeFilteringTestInstance& other);
283 
284 	struct FilterCase
285 	{
286 		int						textureIndex;
287 		tcu::Vec2				bottomLeft;
288 		tcu::Vec2				topRight;
289 
FilterCasevkt::texture::__anon640f863c0111::TextureCubeFilteringTestInstance::FilterCase290 		FilterCase (void)
291 			: textureIndex(-1)
292 		{
293 		}
294 
FilterCasevkt::texture::__anon640f863c0111::TextureCubeFilteringTestInstance::FilterCase295 		FilterCase (int tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
296 			: textureIndex	(tex_)
297 			, bottomLeft	(bottomLeft_)
298 			, topRight		(topRight_)
299 		{
300 		}
301 	};
302 
303 	const ParameterType			m_testParameters;
304 	vector<TestTextureCubeSp>	m_textures;
305 	vector<FilterCase>			m_cases;
306 	TextureRenderer				m_renderer;
307 	int							m_caseNdx;
308 };
309 
TextureCubeFilteringTestInstance(Context & context,const ParameterType & testParameters)310 TextureCubeFilteringTestInstance::TextureCubeFilteringTestInstance (Context& context, const ParameterType& testParameters)
311 	: TestInstance			(context)
312 	, m_testParameters		(testParameters)
313 	, m_renderer			(context, testParameters.sampleCount, TEXCUBE_VIEWPORT_SIZE, TEXCUBE_VIEWPORT_SIZE)
314 	, m_caseNdx				(0)
315 {
316 	const int						numLevels	= deLog2Floor32(m_testParameters.size)+1;
317 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
318 	const tcu::Vec4					cBias		= fmtInfo.valueMin;
319 	const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
320 
321 	if ((testParameters.wrapS == Sampler::MIRRORED_ONCE ||
322 		testParameters.wrapT == Sampler::MIRRORED_ONCE) &&
323 		!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_sampler_mirror_clamp_to_edge"))
324 		TCU_THROW(NotSupportedError, "VK_KHR_sampler_mirror_clamp_to_edge not supported");
325 
326 	m_textures.reserve(2);
327 	for (int ndx = 0; ndx < 2; ndx++)
328 		m_textures.push_back(TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(m_testParameters.format), m_testParameters.size)));
329 
330 	// Fill first with gradient texture.
331 	static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
332 	{
333 		{ tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
334 		{ tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
335 		{ tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
336 		{ tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
337 		{ tcu::Vec4(0.0f, 0.0f, 0.0f, 0.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
338 		{ tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
339 	};
340 
341 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
342 	{
343 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
344 		{
345 			tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
346 		}
347 	}
348 
349 	// Fill second with grid texture.
350 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
351 	{
352 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
353 		{
354 			const deUint32	step	= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
355 			const deUint32	rgb		= step*levelNdx*face;
356 			const deUint32	colorA	= 0xff000000 | rgb;
357 			const deUint32	colorB	= 0xff000000 | ~rgb;
358 
359 			tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
360 		}
361 	}
362 
363 	// Upload.
364 	for (vector<TestTextureCubeSp>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
365 	{
366 		m_renderer.addCubeTexture(*i);
367 	}
368 
369 	// Compute cases
370 	{
371 		const int tex0	= 0;
372 		const int tex1	= m_textures.size() > 1 ? 1 : 0;
373 
374 		if (m_testParameters.onlySampleFaceInterior)
375 		{
376 			m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));	// minification
377 			m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f,  0.8f)));	// magnification
378 			m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));	// minification
379 			m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f,  0.5f)));		// magnification
380 		}
381 		else
382 		{
383 			m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f)));	// minification
384 
385 			m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f)));	// magnification
386 			m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));	// minification
387 			m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f)));	// magnification
388 		}
389 	}
390 }
391 
~TextureCubeFilteringTestInstance(void)392 TextureCubeFilteringTestInstance::~TextureCubeFilteringTestInstance (void)
393 {
394 }
395 
getFaceDesc(const tcu::CubeFace face)396 const char* getFaceDesc (const tcu::CubeFace face)
397 {
398 	switch (face)
399 	{
400 		case tcu::CUBEFACE_NEGATIVE_X:	return "-X";
401 		case tcu::CUBEFACE_POSITIVE_X:	return "+X";
402 		case tcu::CUBEFACE_NEGATIVE_Y:	return "-Y";
403 		case tcu::CUBEFACE_POSITIVE_Y:	return "+Y";
404 		case tcu::CUBEFACE_NEGATIVE_Z:	return "-Z";
405 		case tcu::CUBEFACE_POSITIVE_Z:	return "+Z";
406 		default:
407 			DE_ASSERT(false);
408 			return DE_NULL;
409 	}
410 }
411 
iterate(void)412 tcu::TestStatus TextureCubeFilteringTestInstance::iterate (void)
413 {
414 	tcu::TestLog&						log			= m_context.getTestContext().getLog();
415 
416 	const pipeline::TestTextureCube&	texture		= m_renderer.getCubeTexture(m_cases[m_caseNdx].textureIndex);
417 	const tcu::TextureFormat			texFmt		= texture.getTextureFormat();
418 	const tcu::TextureFormatInfo		fmtInfo		= tcu::getTextureFormatInfo(texFmt);
419 	const FilterCase&					curCase		= m_cases[m_caseNdx];
420 	ReferenceParams						refParams	(TEXTURETYPE_CUBE);
421 
422 	// Params for reference computation.
423 	refParams.sampler					= util::createSampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, m_testParameters.minFilter, m_testParameters.magFilter);
424 	refParams.sampler.seamlessCubeMap	= true;
425 	refParams.samplerType				= getSamplerType(texFmt);
426 	refParams.lodMode					= LODMODE_EXACT;
427 	refParams.colorBias					= fmtInfo.lookupBias;
428 	refParams.colorScale				= fmtInfo.lookupScale;
429 
430 	log << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
431 
432 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
433 	{
434 		const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
435 		tcu::Surface			rendered	(m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
436 		vector<float>			texCoord;
437 
438 		computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
439 
440 		log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
441 
442 		// \todo Log texture coordinates.
443 
444 		m_renderer.renderQuad(rendered, curCase.textureIndex, &texCoord[0], refParams);
445 
446 		{
447 			const bool				isNearestOnly	= m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
448 			const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
449 			const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
450 			const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
451 			tcu::LodPrecision		lodPrecision;
452 			tcu::LookupPrecision	lookupPrecision;
453 
454 			lodPrecision.derivateBits		= 10;
455 			lodPrecision.lodBits			= 5;
456 			lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
457 			lookupPrecision.coordBits		= tcu::IVec3(10,10,10);
458 			lookupPrecision.uvwBits			= tcu::IVec3(6,6,0);
459 			lookupPrecision.colorMask		= getCompareMask(pixelFormat);
460 
461 			const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::TextureCubeView)texture.getTexture(),
462 														   &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
463 
464 			if (!isHighQuality)
465 			{
466 				// Evaluate against lower precision requirements.
467 				lodPrecision.lodBits	= 4;
468 				lookupPrecision.uvwBits	= tcu::IVec3(4,4,0);
469 
470 				log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
471 
472 				const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::TextureCubeView)texture.getTexture(),
473 													  &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
474 
475 				if (!isOk)
476 				{
477 					log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
478 					return tcu::TestStatus::fail("Image verification failed");
479 				}
480 			}
481 		}
482 	}
483 
484 	m_caseNdx += 1;
485 	return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
486 }
487 
488 // 2D array filtering
489 
490 class Texture2DArrayFilteringTestInstance : public TestInstance
491 {
492 public:
493 	typedef Texture2DArrayTestCaseParameters	ParameterType;
494 
495 												Texture2DArrayFilteringTestInstance		(Context& context, const ParameterType& testParameters);
496 												~Texture2DArrayFilteringTestInstance	(void);
497 
498 	virtual tcu::TestStatus						iterate									(void);
499 
500 private:
501 												Texture2DArrayFilteringTestInstance		(const Texture2DArrayFilteringTestInstance&);
502 	Texture2DArrayFilteringTestInstance&		operator=								(const Texture2DArrayFilteringTestInstance&);
503 
504 	struct FilterCase
505 	{
506 		int							textureIndex;
507 		tcu::Vec2					lod;
508 		tcu::Vec2					offset;
509 		tcu::Vec2					layerRange;
510 
FilterCasevkt::texture::__anon640f863c0111::Texture2DArrayFilteringTestInstance::FilterCase511 		FilterCase (void)
512 			: textureIndex(-1)
513 		{
514 		}
515 
FilterCasevkt::texture::__anon640f863c0111::Texture2DArrayFilteringTestInstance::FilterCase516 		FilterCase (const int tex_, const tcu::Vec2& lod_, const tcu::Vec2& offset_, const tcu::Vec2& layerRange_)
517 			: textureIndex	(tex_)
518 			, lod			(lod_)
519 			, offset		(offset_)
520 			, layerRange	(layerRange_)
521 		{
522 		}
523 	};
524 
525 	const ParameterType				m_testParameters;
526 	vector<TestTexture2DArraySp>	m_textures;
527 	vector<FilterCase>				m_cases;
528 	TextureRenderer					m_renderer;
529 	int								m_caseNdx;
530 };
531 
Texture2DArrayFilteringTestInstance(Context & context,const ParameterType & testParameters)532 Texture2DArrayFilteringTestInstance::Texture2DArrayFilteringTestInstance (Context& context, const ParameterType& testParameters)
533 	: TestInstance			(context)
534 	, m_testParameters		(testParameters)
535 	, m_renderer			(context, testParameters.sampleCount, TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT)
536 	, m_caseNdx				(0)
537 {
538 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
539 	const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
540 	const tcu::Vec4					cBias		= fmtInfo.valueMin;
541 	const int						numLevels	= deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height)) + 1;
542 
543 	if ((testParameters.wrapS == Sampler::MIRRORED_ONCE ||
544 		testParameters.wrapT == Sampler::MIRRORED_ONCE) &&
545 		!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_sampler_mirror_clamp_to_edge"))
546 		TCU_THROW(NotSupportedError, "VK_KHR_sampler_mirror_clamp_to_edge not supported");
547 
548 	// Create textures.
549 	m_textures.reserve(2);
550 	for (int ndx = 0; ndx < 2; ndx++)
551 		m_textures.push_back(TestTexture2DArraySp(new pipeline::TestTexture2DArray(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.numLayers)));
552 
553 	const tcu::IVec4 levelSwz[] =
554 	{
555 		tcu::IVec4(0,1,2,3),
556 		tcu::IVec4(2,1,3,0),
557 		tcu::IVec4(3,0,1,2),
558 		tcu::IVec4(1,3,2,0),
559 	};
560 
561 	// Fill first gradient texture (gradient direction varies between layers).
562 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
563 	{
564 		for (int layerNdx = 0; layerNdx < m_testParameters.numLayers; layerNdx++)
565 		{
566 			const tcu::PixelBufferAccess levelBuf = m_textures[0]->getLevel(levelNdx, layerNdx);
567 
568 			const tcu::IVec4	swz		= levelSwz[layerNdx%DE_LENGTH_OF_ARRAY(levelSwz)];
569 			const tcu::Vec4		gMin	= tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
570 			const tcu::Vec4		gMax	= tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
571 
572 			tcu::fillWithComponentGradients(levelBuf, gMin, gMax);
573 		}
574 	}
575 
576 	// Fill second with grid texture (each layer has unique colors).
577 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
578 	{
579 		for (int layerNdx = 0; layerNdx < m_testParameters.numLayers; layerNdx++)
580 		{
581 			const tcu::PixelBufferAccess levelBuf = m_textures[1]->getLevel(levelNdx, layerNdx);
582 
583 			const deUint32	step	= 0x00ffffff / (numLevels*m_testParameters.numLayers - 1);
584 			const deUint32	rgb		= step * (levelNdx + layerNdx*numLevels);
585 			const deUint32	colorA	= 0xff000000 | rgb;
586 			const deUint32	colorB	= 0xff000000 | ~rgb;
587 
588 			tcu::fillWithGrid(levelBuf, 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
589 		}
590 	}
591 
592 	// Upload.
593 	for (vector<TestTexture2DArraySp>::const_iterator i = m_textures.begin(); i != m_textures.end(); i++)
594 	{
595 		m_renderer.add2DArrayTexture(*i);
596 	}
597 
598 	// Test cases
599 	m_cases.push_back(FilterCase(0,	tcu::Vec2( 1.5f,  2.8f  ),	tcu::Vec2(-1.0f, -2.7f), tcu::Vec2(-0.5f, float(m_testParameters.numLayers)+0.5f)));
600 	m_cases.push_back(FilterCase(1,	tcu::Vec2( 0.2f,  0.175f),	tcu::Vec2(-2.0f, -3.7f), tcu::Vec2(-0.5f, float(m_testParameters.numLayers)+0.5f)));
601 	m_cases.push_back(FilterCase(1,	tcu::Vec2(-0.8f, -2.3f  ),	tcu::Vec2( 0.2f, -0.1f), tcu::Vec2(float(m_testParameters.numLayers)+0.5f, -0.5f)));
602 	m_cases.push_back(FilterCase(0,	tcu::Vec2(-2.0f, -1.5f  ),	tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
603 }
604 
~Texture2DArrayFilteringTestInstance(void)605 Texture2DArrayFilteringTestInstance::~Texture2DArrayFilteringTestInstance (void)
606 {
607 }
608 
iterate(void)609 tcu::TestStatus Texture2DArrayFilteringTestInstance::iterate (void)
610 {
611 	tcu::TestLog&						log			= m_context.getTestContext().getLog();
612 
613 	const FilterCase&					curCase		= m_cases[m_caseNdx];
614 	const pipeline::TestTexture2DArray&	texture		= m_renderer.get2DArrayTexture(curCase.textureIndex);
615 	const tcu::TextureFormat			texFmt		= texture.getTextureFormat();
616 	const tcu::TextureFormatInfo		fmtInfo		= tcu::getTextureFormatInfo(texFmt);
617 	ReferenceParams						refParams	(TEXTURETYPE_2D_ARRAY);
618 	tcu::Surface						rendered	(m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
619 	tcu::Vec3							texCoord[4];
620 	const float* const					texCoordPtr	= (const float*)&texCoord[0];
621 
622 	// Params for reference computation.
623 
624 	refParams.sampler		= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
625 	refParams.samplerType	= getSamplerType(texFmt);
626 	refParams.lodMode		= LODMODE_EXACT;
627 	refParams.colorBias		= fmtInfo.lookupBias;
628 	refParams.colorScale	= fmtInfo.lookupScale;
629 
630 	// Compute texture coordinates.
631 	log << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
632 
633 	{
634 		const float	lodX	= curCase.lod.x();
635 		const float	lodY	= curCase.lod.y();
636 		const float	oX		= curCase.offset.x();
637 		const float	oY		= curCase.offset.y();
638 		const float	sX		= deFloatExp2(lodX) * float(m_renderer.getRenderWidth()) / float(m_textures[0]->getTexture().getWidth());
639 		const float	sY		= deFloatExp2(lodY) * float(m_renderer.getRenderHeight()) / float(m_textures[0]->getTexture().getHeight());
640 		const float	l0		= curCase.layerRange.x();
641 		const float	l1		= curCase.layerRange.y();
642 
643 		texCoord[0] = tcu::Vec3(oX,		oY,		l0);
644 		texCoord[1] = tcu::Vec3(oX,		oY+sY,	l0*0.5f + l1*0.5f);
645 		texCoord[2] = tcu::Vec3(oX+sX,	oY,		l0*0.5f + l1*0.5f);
646 		texCoord[3] = tcu::Vec3(oX+sX,	oY+sY,	l1);
647 	}
648 
649 	m_renderer.renderQuad(rendered, curCase.textureIndex, texCoordPtr, refParams);
650 
651 	{
652 
653 		const bool				isNearestOnly	= m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
654 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
655 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
656 		const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
657 		tcu::LodPrecision		lodPrecision;
658 		tcu::LookupPrecision	lookupPrecision;
659 
660 		lodPrecision.derivateBits		= 18;
661 		lodPrecision.lodBits			= 6;
662 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
663 		lookupPrecision.coordBits		= tcu::IVec3(20,20,20);
664 		lookupPrecision.uvwBits			= tcu::IVec3(7,7,0);
665 		lookupPrecision.colorMask		= getCompareMask(pixelFormat);
666 
667 		const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DArrayView)texture.getTexture(),
668 													   texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
669 
670 		if (!isHighQuality)
671 		{
672 			// Evaluate against lower precision requirements.
673 			lodPrecision.lodBits	= 4;
674 			lookupPrecision.uvwBits	= tcu::IVec3(4,4,0);
675 
676 			log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
677 
678 			const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DArrayView)texture.getTexture(),
679 												  texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
680 
681 			if (!isOk)
682 			{
683 				log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
684 				return tcu::TestStatus::fail("Image verification failed");
685 			}
686 		}
687 	}
688 
689 	m_caseNdx += 1;
690 	return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
691 }
692 
693 // 3D filtering
694 
695 class Texture3DFilteringTestInstance : public TestInstance
696 {
697 public:
698 	typedef Texture3DTestCaseParameters	ParameterType;
699 
700 										Texture3DFilteringTestInstance		(Context& context, const ParameterType& testParameters);
701 										~Texture3DFilteringTestInstance		(void);
702 
703 	virtual tcu::TestStatus				iterate								(void);
704 
705 private:
706 										Texture3DFilteringTestInstance		(const Texture3DFilteringTestInstance& other);
707 	Texture3DFilteringTestInstance&		operator=							(const Texture3DFilteringTestInstance& other);
708 
709 	struct FilterCase
710 	{
711 		int						textureIndex;
712 		tcu::Vec3				lod;
713 		tcu::Vec3				offset;
714 
FilterCasevkt::texture::__anon640f863c0111::Texture3DFilteringTestInstance::FilterCase715 		FilterCase (void)
716 			: textureIndex(-1)
717 		{
718 		}
719 
FilterCasevkt::texture::__anon640f863c0111::Texture3DFilteringTestInstance::FilterCase720 		FilterCase (const int tex_, const tcu::Vec3& lod_, const tcu::Vec3& offset_)
721 			: textureIndex	(tex_)
722 			, lod			(lod_)
723 			, offset		(offset_)
724 		{
725 		}
726 	};
727 
728 	const ParameterType			m_testParameters;
729 	vector<TestTexture3DSp>		m_textures;
730 	vector<FilterCase>			m_cases;
731 	TextureRenderer				m_renderer;
732 	int							m_caseNdx;
733 };
734 
Texture3DFilteringTestInstance(Context & context,const ParameterType & testParameters)735 Texture3DFilteringTestInstance::Texture3DFilteringTestInstance (Context& context, const ParameterType& testParameters)
736 	: TestInstance			(context)
737 	, m_testParameters		(testParameters)
738 	, m_renderer			(context, testParameters.sampleCount, TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT)
739 	, m_caseNdx				(0)
740 {
741 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
742 	const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
743 	const tcu::Vec4					cBias		= fmtInfo.valueMin;
744 	const int						numLevels	= deLog2Floor32(de::max(de::max(m_testParameters.width, m_testParameters.height), m_testParameters.depth)) + 1;
745 
746 	if ((testParameters.wrapS == Sampler::MIRRORED_ONCE ||
747 		testParameters.wrapT == Sampler::MIRRORED_ONCE ||
748 		testParameters.wrapR == Sampler::MIRRORED_ONCE) &&
749 		!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_sampler_mirror_clamp_to_edge"))
750 		TCU_THROW(NotSupportedError, "VK_KHR_sampler_mirror_clamp_to_edge not supported");
751 
752 	// Create textures.
753 	m_textures.reserve(2);
754 	for (int ndx = 0; ndx < 2; ndx++)
755 		m_textures.push_back(TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.depth)));
756 
757 	// Fill first gradient texture.
758 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
759 	{
760 		const tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
761 		const tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
762 
763 		tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, 0), gMin, gMax);
764 	}
765 
766 	// Fill second with grid texture.
767 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
768 	{
769 		const deUint32	step	= 0x00ffffff / numLevels;
770 		const deUint32	rgb		= step*levelNdx;
771 		const deUint32	colorA	= 0xff000000 | rgb;
772 		const deUint32	colorB	= 0xff000000 | ~rgb;
773 
774 		tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, 0), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
775 	}
776 
777 	// Upload.
778 	for (vector<TestTexture3DSp>::const_iterator i = m_textures.begin(); i != m_textures.end(); i++)
779 	{
780 		m_renderer.add3DTexture(*i);
781 	}
782 
783 	// Test cases
784 	m_cases.push_back(FilterCase(0,	tcu::Vec3(1.5f, 2.8f, 1.0f),	tcu::Vec3(-1.0f, -2.7f, -2.275f)));
785 	m_cases.push_back(FilterCase(0,	tcu::Vec3(-2.0f, -1.5f, -1.8f),	tcu::Vec3(-0.1f, 0.9f, -0.25f)));
786 	m_cases.push_back(FilterCase(1,	tcu::Vec3(0.2f, 0.175f, 0.3f),	tcu::Vec3(-2.0f, -3.7f, -1.825f)));
787 	m_cases.push_back(FilterCase(1,	tcu::Vec3(-0.8f, -2.3f, -2.5f),	tcu::Vec3(0.2f, -0.1f, 1.325f)));
788 }
789 
~Texture3DFilteringTestInstance(void)790 Texture3DFilteringTestInstance::~Texture3DFilteringTestInstance (void)
791 {
792 }
793 
iterate(void)794 tcu::TestStatus Texture3DFilteringTestInstance::iterate (void)
795 {
796 	tcu::TestLog&						log			= m_context.getTestContext().getLog();
797 
798 	const pipeline::TestTexture3D&	texture		= m_renderer.get3DTexture(m_cases[m_caseNdx].textureIndex);
799 	const tcu::TextureFormat		texFmt		= texture.getTextureFormat();
800 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
801 	const FilterCase&				curCase		= m_cases[m_caseNdx];
802 	ReferenceParams					refParams	(TEXTURETYPE_3D);
803 	tcu::Surface					rendered	(m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
804 	tcu::Vec3						texCoord[4];
805 	const float* const				texCoordPtr	= (const float*)&texCoord[0];
806 
807 	// Params for reference computation.
808 	refParams.sampler		= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.wrapR, m_testParameters.minFilter, m_testParameters.magFilter);
809 	refParams.samplerType	= getSamplerType(texFmt);
810 	refParams.lodMode		= LODMODE_EXACT;
811 	refParams.colorBias		= fmtInfo.lookupBias;
812 	refParams.colorScale	= fmtInfo.lookupScale;
813 
814 	// Compute texture coordinates.
815 	log << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
816 
817 	{
818 		const float	lodX	= curCase.lod.x();
819 		const float	lodY	= curCase.lod.y();
820 		const float	lodZ	= curCase.lod.z();
821 		const float	oX		= curCase.offset.x();
822 		const float	oY		= curCase.offset.y();
823 		const float oZ		= curCase.offset.z();
824 		const float	sX		= deFloatExp2(lodX) * float(m_renderer.getRenderWidth())										/ float(m_textures[0]->getTexture().getWidth());
825 		const float	sY		= deFloatExp2(lodY) * float(m_renderer.getRenderHeight())										/ float(m_textures[0]->getTexture().getHeight());
826 		const float	sZ		= deFloatExp2(lodZ) * float(de::max(m_renderer.getRenderWidth(), m_renderer.getRenderHeight()))	/ float(m_textures[0]->getTexture().getDepth());
827 
828 		texCoord[0] = tcu::Vec3(oX,		oY,		oZ);
829 		texCoord[1] = tcu::Vec3(oX,		oY+sY,	oZ + sZ*0.5f);
830 		texCoord[2] = tcu::Vec3(oX+sX,	oY,		oZ + sZ*0.5f);
831 		texCoord[3] = tcu::Vec3(oX+sX,	oY+sY,	oZ + sZ);
832 	}
833 
834 	m_renderer.renderQuad(rendered, curCase.textureIndex, texCoordPtr, refParams);
835 
836 	{
837 		const bool				isNearestOnly	= m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
838 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
839 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
840 		const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
841 		tcu::LodPrecision		lodPrecision;
842 		tcu::LookupPrecision	lookupPrecision;
843 
844 		lodPrecision.derivateBits		= 18;
845 		lodPrecision.lodBits			= 6;
846 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
847 		lookupPrecision.coordBits		= tcu::IVec3(20,20,20);
848 		lookupPrecision.uvwBits			= tcu::IVec3(7,7,7);
849 		lookupPrecision.colorMask		= getCompareMask(pixelFormat);
850 
851 		const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture3DView)texture.getTexture(),
852 													   texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
853 
854 		if (!isHighQuality)
855 		{
856 			// Evaluate against lower precision requirements.
857 			lodPrecision.lodBits	= 4;
858 			lookupPrecision.uvwBits	= tcu::IVec3(4,4,4);
859 
860 			log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
861 
862 			const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture3DView)texture.getTexture(),
863 												  texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
864 
865 			if (!isOk)
866 			{
867 				log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
868 				return tcu::TestStatus::fail("Image verification failed");
869 			}
870 		}
871 	}
872 
873 	m_caseNdx += 1;
874 	return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
875 }
876 
verifierCanBeUsed(const VkFormat format,const Sampler::FilterMode minFilter,const Sampler::FilterMode magFilter)877 bool verifierCanBeUsed (const VkFormat format, const Sampler::FilterMode minFilter, const Sampler::FilterMode magFilter)
878 {
879 	const tcu::TextureFormat				textureFormat		= mapVkFormat(format);
880 	const tcu::TextureChannelClass			textureChannelClass	= tcu::getTextureChannelClass(textureFormat.type);
881 
882 	return !(!(textureChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
883 			   textureChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
884 			   textureChannelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) &&
885 			  (tcu::TexVerifierUtil::isLinearFilter(minFilter) || tcu::TexVerifierUtil::isLinearFilter(magFilter)));
886 }
887 
populateTextureFilteringTests(tcu::TestCaseGroup * textureFilteringTests)888 void populateTextureFilteringTests (tcu::TestCaseGroup* textureFilteringTests)
889 {
890 	tcu::TestContext&	testCtx		= textureFilteringTests->getTestContext();
891 
892 	static const struct
893 	{
894 		const char* const			name;
895 		const Sampler::WrapMode		mode;
896 	} wrapModes[] =
897 	{
898 		{ "repeat",					Sampler::REPEAT_GL			},
899 		{ "mirrored_repeat",		Sampler::MIRRORED_REPEAT_GL	},
900 		{ "clamp_to_edge",			Sampler::CLAMP_TO_EDGE		},
901 		{ "clamp_to_border",		Sampler::CLAMP_TO_BORDER	},
902 		{ "mirror_clamp_to_edge",	Sampler::MIRRORED_ONCE		}
903 	};
904 
905 	static const struct
906 	{
907 		const char* const			name;
908 		const Sampler::FilterMode	mode;
909 	} minFilterModes[] =
910 	{
911 		{ "nearest",				Sampler::NEAREST					},
912 		{ "linear",					Sampler::LINEAR						},
913 		{ "nearest_mipmap_nearest",	Sampler::NEAREST_MIPMAP_NEAREST		},
914 		{ "linear_mipmap_nearest",	Sampler::LINEAR_MIPMAP_NEAREST		},
915 		{ "nearest_mipmap_linear",	Sampler::NEAREST_MIPMAP_LINEAR		},
916 		{ "linear_mipmap_linear",	Sampler::LINEAR_MIPMAP_LINEAR		}
917 	};
918 
919 	static const struct
920 	{
921 		const char* const			name;
922 		const Sampler::FilterMode	mode;
923 	} magFilterModes[] =
924 	{
925 		{ "nearest",				Sampler::NEAREST },
926 		{ "linear",					Sampler::LINEAR	 }
927 	};
928 
929 	static const struct
930 	{
931 		const int	width;
932 		const int	height;
933 	} sizes2D[] =
934 	{
935 		{   4,	  8 },
936 		{  32,	 64 },
937 		{ 128,	128	},
938 		{   3,	  7 },
939 		{  31,	 55 },
940 		{ 127,	 99 }
941 	};
942 
943 	static const struct
944 	{
945 		const int	size;
946 	} sizesCube[] =
947 	{
948 		{   8 },
949 		{  64 },
950 		{ 128 },
951 		{   7 },
952 		{  63 }
953 	};
954 
955 	static const struct
956 	{
957 		const int	width;
958 		const int	height;
959 		const int	numLayers;
960 	} sizes2DArray[] =
961 	{
962 		{   4,   8,   8 },
963 		{  32,  64,  16 },
964 		{ 128,  32,  64 },
965 		{   3,   7,   5 },
966 		{  63,  63,  63 }
967 	};
968 
969 	static const struct
970 	{
971 		const int	width;
972 		const int	height;
973 		const int	depth;
974 	} sizes3D[] =
975 	{
976 		{   4,   8,   8 },
977 		{  32,  64,  16 },
978 		{ 128,  32,  64 },
979 		{   3,   7,   5 },
980 		{  63,  63,  63 }
981 	};
982 
983 	static const struct
984 	{
985 		const char* const	name;
986 		const VkFormat		format;
987 	} filterableFormatsByType[] =
988 	{
989 		{ "r16g16b16a16_sfloat",	VK_FORMAT_R16G16B16A16_SFLOAT		},
990 		{ "b10g11r11_ufloat",		VK_FORMAT_B10G11R11_UFLOAT_PACK32	},
991 		{ "e5b9g9r9_ufloat",		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32	},
992 		{ "r8g8b8a8_unorm",			VK_FORMAT_R8G8B8A8_UNORM			},
993 		{ "r8g8b8a8_snorm",			VK_FORMAT_R8G8B8A8_SNORM			},
994 		{ "r5g6b5_unorm",			VK_FORMAT_R5G6B5_UNORM_PACK16		},
995 		{ "r4g4b4a4_unorm",			VK_FORMAT_R4G4B4A4_UNORM_PACK16		},
996 		{ "r5g5b5a1_unorm",			VK_FORMAT_R5G5B5A1_UNORM_PACK16		},
997 		{ "a8b8g8r8_srgb",			VK_FORMAT_A8B8G8R8_SRGB_PACK32		},
998 		{ "a1r5g5b5_unorm",			VK_FORMAT_A1R5G5B5_UNORM_PACK16		}
999 	};
1000 
1001 	// 2D texture filtering.
1002 	{
1003 		de::MovePtr<tcu::TestCaseGroup>	group2D				(new tcu::TestCaseGroup(testCtx, "2d", "2D Texture Filtering"));
1004 
1005 		de::MovePtr<tcu::TestCaseGroup>	formatsGroup		(new tcu::TestCaseGroup(testCtx, "formats", "2D Texture Formats"));
1006 		de::MovePtr<tcu::TestCaseGroup>	sizesGroup			(new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1007 		de::MovePtr<tcu::TestCaseGroup>	combinationsGroup	(new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1008 
1009 		// Formats.
1010 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1011 		{
1012 			const string					filterGroupName	= filterableFormatsByType[fmtNdx].name;
1013 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1014 
1015 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1016 			{
1017 				const Sampler::FilterMode	minFilter		= minFilterModes[filterNdx].mode;
1018 				const bool					isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1019 				const string				name			= minFilterModes[filterNdx].name;
1020 				Texture2DTestCaseParameters	testParameters;
1021 
1022 				testParameters.format		= filterableFormatsByType[fmtNdx].format;
1023 				testParameters.minFilter	= minFilter;
1024 				testParameters.magFilter	= isMipmap ? Sampler::LINEAR : minFilter;
1025 				testParameters.mipmaps		= true;
1026 
1027 				testParameters.wrapS		= Sampler::REPEAT_GL;
1028 				testParameters.wrapT		= Sampler::REPEAT_GL;
1029 				testParameters.width		= 64;
1030 				testParameters.height		= 64;
1031 
1032 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1033 				testParameters.programs.push_back(PROGRAM_2D_UINT);
1034 
1035 				// Some combinations of the tests have to be skipped due to the restrictions of the verifiers.
1036 				if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1037 				{
1038 					filterGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1039 				}
1040 			}
1041 			formatsGroup->addChild(filterGroup.release());
1042 		}
1043 
1044 		// Sizes.
1045 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
1046 		{
1047 			const string					filterGroupName = de::toString(sizes2D[sizeNdx].width) + "x" + de::toString(sizes2D[sizeNdx].height);
1048 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1049 
1050 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1051 			{
1052 				const Sampler::FilterMode	minFilter		= minFilterModes[filterNdx].mode;
1053 				const bool					isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1054 				const string				name			= minFilterModes[filterNdx].name;
1055 				Texture2DTestCaseParameters	testParameters;
1056 
1057 				testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1058 				testParameters.minFilter	= minFilter;
1059 				testParameters.magFilter	= isMipmap ? Sampler::LINEAR : minFilter;
1060 				testParameters.mipmaps		= true;
1061 
1062 				testParameters.wrapS		= Sampler::REPEAT_GL;
1063 				testParameters.wrapT		= Sampler::REPEAT_GL;
1064 				testParameters.width		= sizes2D[sizeNdx].width;
1065 				testParameters.height		= sizes2D[sizeNdx].height;
1066 
1067 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1068 
1069 				filterGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1070 			}
1071 			sizesGroup->addChild(filterGroup.release());
1072 		}
1073 
1074 		// Wrap modes.
1075 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1076 		{
1077 			de::MovePtr<tcu::TestCaseGroup>	minFilterGroup(new tcu::TestCaseGroup(testCtx, minFilterModes[minFilterNdx].name, ""));
1078 
1079 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1080 			{
1081 				de::MovePtr<tcu::TestCaseGroup>	magFilterGroup(new tcu::TestCaseGroup(testCtx, magFilterModes[magFilterNdx].name, ""));
1082 
1083 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1084 				{
1085 					de::MovePtr<tcu::TestCaseGroup>	wrapSGroup(new tcu::TestCaseGroup(testCtx, wrapModes[wrapSNdx].name, ""));
1086 
1087 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1088 					{
1089 						const string	name		= wrapModes[wrapTNdx].name;
1090 						Texture2DTestCaseParameters	testParameters;
1091 
1092 						testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1093 						testParameters.minFilter	= minFilterModes[minFilterNdx].mode;
1094 						testParameters.magFilter	= magFilterModes[magFilterNdx].mode;
1095 						testParameters.mipmaps		= true;
1096 
1097 						testParameters.wrapS		= wrapModes[wrapSNdx].mode;
1098 						testParameters.wrapT		= wrapModes[wrapTNdx].mode;
1099 						testParameters.width		= 63;
1100 						testParameters.height		= 57;
1101 
1102 						testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1103 
1104 						wrapSGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1105 					}
1106 					magFilterGroup->addChild(wrapSGroup.release());
1107 				}
1108 				minFilterGroup->addChild(magFilterGroup.release());
1109 			}
1110 			combinationsGroup->addChild(minFilterGroup.release());
1111 		}
1112 
1113 		group2D->addChild(formatsGroup.release());
1114 		group2D->addChild(sizesGroup.release());
1115 		group2D->addChild(combinationsGroup.release());
1116 
1117 		textureFilteringTests->addChild(group2D.release());
1118 	}
1119 
1120 	// Unnormalized texture filtering.
1121 	{
1122 		de::MovePtr<tcu::TestCaseGroup>	groupUnnormal		(new tcu::TestCaseGroup(testCtx, "unnormal", "Unnormalized Texture Filtering"));
1123 
1124 		de::MovePtr<tcu::TestCaseGroup>	formatsGroup		(new tcu::TestCaseGroup(testCtx, "formats", "2D Texture Formats"));
1125 		de::MovePtr<tcu::TestCaseGroup>	sizesGroup			(new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1126 
1127 		// Formats.
1128 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1129 		{
1130 			const string					filterGroupName	= filterableFormatsByType[fmtNdx].name;
1131 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1132 
1133 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); filterNdx++)
1134 			{
1135 				const Sampler::FilterMode	magFilter		= magFilterModes[filterNdx].mode;
1136 				const string				name			= magFilterModes[filterNdx].name;
1137 				Texture2DTestCaseParameters	testParameters;
1138 
1139 				testParameters.unnormal		= true;
1140 
1141 				testParameters.format		= filterableFormatsByType[fmtNdx].format;
1142 				testParameters.minFilter	= magFilter;
1143 				testParameters.magFilter	= magFilter;
1144 				testParameters.mipmaps		= false;
1145 
1146 				testParameters.wrapS		= ((fmtNdx ^ filterNdx) & 1) ? Sampler::CLAMP_TO_EDGE : Sampler::CLAMP_TO_BORDER;
1147 				testParameters.wrapT		= ((fmtNdx ^ filterNdx) & 2) ? Sampler::CLAMP_TO_EDGE : Sampler::CLAMP_TO_BORDER;
1148 				testParameters.width		= 64;
1149 				testParameters.height		= 64;
1150 
1151 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1152 				testParameters.programs.push_back(PROGRAM_2D_UINT);
1153 
1154 				// Some combinations of the tests have to be skipped due to the restrictions of the verifiers.
1155 				if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1156 				{
1157 					filterGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1158 				}
1159 			}
1160 			formatsGroup->addChild(filterGroup.release());
1161 		}
1162 
1163 		// Sizes.
1164 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
1165 		{
1166 			const string					filterGroupName = de::toString(sizes2D[sizeNdx].width) + "x" + de::toString(sizes2D[sizeNdx].height);
1167 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1168 
1169 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); filterNdx++)
1170 			{
1171 				const Sampler::FilterMode	magFilter		= magFilterModes[filterNdx].mode;
1172 				const string				name			= magFilterModes[filterNdx].name;
1173 				Texture2DTestCaseParameters	testParameters;
1174 
1175 				testParameters.unnormal		= true;
1176 				testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1177 				testParameters.minFilter	= magFilter;
1178 				testParameters.magFilter	= magFilter;
1179 				testParameters.mipmaps		= false;
1180 
1181 				testParameters.wrapS		= ((sizeNdx ^ filterNdx) & 1) ? Sampler::CLAMP_TO_EDGE : Sampler::CLAMP_TO_BORDER;
1182 				testParameters.wrapT		= ((sizeNdx ^ filterNdx) & 2) ? Sampler::CLAMP_TO_EDGE : Sampler::CLAMP_TO_BORDER;
1183 				testParameters.width		= sizes2D[sizeNdx].width;
1184 				testParameters.height		= sizes2D[sizeNdx].height;
1185 
1186 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1187 
1188 				filterGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1189 			}
1190 			sizesGroup->addChild(filterGroup.release());
1191 		}
1192 
1193 		groupUnnormal->addChild(formatsGroup.release());
1194 		groupUnnormal->addChild(sizesGroup.release());
1195 
1196 		textureFilteringTests->addChild(groupUnnormal.release());
1197 	}
1198 
1199 	// Cube map texture filtering.
1200 	{
1201 		de::MovePtr<tcu::TestCaseGroup>	groupCube				(new tcu::TestCaseGroup(testCtx, "cube", "Cube Map Texture Filtering"));
1202 
1203 		de::MovePtr<tcu::TestCaseGroup>	formatsGroup			(new tcu::TestCaseGroup(testCtx, "formats", "2D Texture Formats"));
1204 		de::MovePtr<tcu::TestCaseGroup>	sizesGroup				(new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1205 		de::MovePtr<tcu::TestCaseGroup>	combinationsGroup		(new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1206 		de::MovePtr<tcu::TestCaseGroup>	onlyFaceInteriorGroup	(new tcu::TestCaseGroup(testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges"));
1207 
1208 		// Formats.
1209 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1210 		{
1211 			const string					filterGroupName = filterableFormatsByType[fmtNdx].name;
1212 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1213 
1214 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1215 			{
1216 				const Sampler::FilterMode				minFilter	= minFilterModes[filterNdx].mode;
1217 				const bool								isMipmap	= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1218 				const string							name		= minFilterModes[filterNdx].name;
1219 				TextureCubeFilteringTestCaseParameters	testParameters;
1220 
1221 				testParameters.format					= filterableFormatsByType[fmtNdx].format;
1222 				testParameters.minFilter				= minFilter;
1223 				testParameters.magFilter				= isMipmap ? Sampler::LINEAR : minFilter;
1224 
1225 				testParameters.wrapS					= Sampler::REPEAT_GL;
1226 				testParameters.wrapT					= Sampler::REPEAT_GL;
1227 				testParameters.onlySampleFaceInterior	= false;
1228 				testParameters.size						= 64;
1229 
1230 				testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1231 				testParameters.programs.push_back(PROGRAM_CUBE_UINT);
1232 
1233 				// Some tests have to be skipped due to the restrictions of the verifiers.
1234 				if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1235 				{
1236 					filterGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1237 				}
1238 			}
1239 			formatsGroup->addChild(filterGroup.release());
1240 		}
1241 
1242 		// Sizes.
1243 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
1244 		{
1245 			const string					filterGroupName = de::toString(sizesCube[sizeNdx].size) + "x" + de::toString(sizesCube[sizeNdx].size);
1246 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1247 
1248 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1249 			{
1250 				const Sampler::FilterMode				minFilter		= minFilterModes[filterNdx].mode;
1251 				const bool								isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1252 				const string							name			= minFilterModes[filterNdx].name;
1253 				TextureCubeFilteringTestCaseParameters	testParameters;
1254 
1255 				testParameters.format					= VK_FORMAT_R8G8B8A8_UNORM;
1256 				testParameters.minFilter				= minFilter;
1257 				testParameters.magFilter				= isMipmap ? Sampler::LINEAR : minFilter;
1258 				testParameters.wrapS					= Sampler::REPEAT_GL;
1259 				testParameters.wrapT					= Sampler::REPEAT_GL;
1260 				testParameters.onlySampleFaceInterior	= false;
1261 				testParameters.size						= sizesCube[sizeNdx].size;
1262 
1263 				testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1264 
1265 				filterGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1266 
1267 			}
1268 			sizesGroup->addChild(filterGroup.release());
1269 		}
1270 
1271 		// Filter/wrap mode combinations.
1272 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1273 		{
1274 			de::MovePtr<tcu::TestCaseGroup>	minFilterGroup(new tcu::TestCaseGroup(testCtx, minFilterModes[minFilterNdx].name, ""));
1275 
1276 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1277 			{
1278 				de::MovePtr<tcu::TestCaseGroup>	magFilterGroup(new tcu::TestCaseGroup(testCtx, magFilterModes[magFilterNdx].name, ""));
1279 
1280 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1281 				{
1282 					de::MovePtr<tcu::TestCaseGroup>	wrapSGroup(new tcu::TestCaseGroup(testCtx, wrapModes[wrapSNdx].name, ""));
1283 
1284 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1285 					{
1286 						const string							name			= wrapModes[wrapTNdx].name;
1287 						TextureCubeFilteringTestCaseParameters	testParameters;
1288 
1289 						testParameters.format					= VK_FORMAT_R8G8B8A8_UNORM;
1290 						testParameters.minFilter				= minFilterModes[minFilterNdx].mode;
1291 						testParameters.magFilter				= magFilterModes[magFilterNdx].mode;
1292 						testParameters.wrapS					= wrapModes[wrapSNdx].mode;
1293 						testParameters.wrapT					= wrapModes[wrapTNdx].mode;
1294 						testParameters.onlySampleFaceInterior	= false;
1295 						testParameters.size						= 63;
1296 
1297 						testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1298 
1299 						wrapSGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1300 					}
1301 					magFilterGroup->addChild(wrapSGroup.release());
1302 				}
1303 				minFilterGroup->addChild(magFilterGroup.release());
1304 			}
1305 			combinationsGroup->addChild(minFilterGroup.release());
1306 		}
1307 
1308 		// Cases with no visible cube edges.
1309 		for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
1310 		{
1311 			const bool								isLinear		= isLinearI != 0;
1312 			const string							name			= isLinear ? "linear" : "nearest";
1313 			TextureCubeFilteringTestCaseParameters	testParameters;
1314 
1315 			testParameters.format					= VK_FORMAT_R8G8B8A8_UNORM;
1316 			testParameters.minFilter				= isLinear ? Sampler::LINEAR : Sampler::NEAREST;
1317 			testParameters.magFilter				= isLinear ? Sampler::LINEAR : Sampler::NEAREST;
1318 			testParameters.wrapS					= Sampler::REPEAT_GL;
1319 			testParameters.wrapT					= Sampler::REPEAT_GL;
1320 			testParameters.onlySampleFaceInterior	= true;
1321 			testParameters.size						= 63;
1322 
1323 			testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1324 
1325 			onlyFaceInteriorGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1326 		}
1327 
1328 		groupCube->addChild(formatsGroup.release());
1329 		groupCube->addChild(sizesGroup.release());
1330 		groupCube->addChild(combinationsGroup.release());
1331 		groupCube->addChild(onlyFaceInteriorGroup.release());
1332 
1333 		textureFilteringTests->addChild(groupCube.release());
1334 	}
1335 
1336 	// 2D array texture filtering.
1337 	{
1338 		de::MovePtr<tcu::TestCaseGroup>	group2DArray		(new tcu::TestCaseGroup(testCtx, "2d_array", "2D Array Texture Filtering"));
1339 
1340 		de::MovePtr<tcu::TestCaseGroup>	formatsGroup		(new tcu::TestCaseGroup(testCtx, "formats", "2D Array Texture Formats"));
1341 		de::MovePtr<tcu::TestCaseGroup>	sizesGroup			(new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1342 		de::MovePtr<tcu::TestCaseGroup>	combinationsGroup	(new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1343 
1344 		// Formats.
1345 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1346 		{
1347 			const string					filterGroupName = filterableFormatsByType[fmtNdx].name;
1348 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1349 
1350 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1351 			{
1352 				const Sampler::FilterMode			minFilter		= minFilterModes[filterNdx].mode;
1353 				const char* const					filterName		= minFilterModes[filterNdx].name;
1354 				const bool							isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1355 				const char* const					formatName		= filterableFormatsByType[fmtNdx].name;
1356 				const string						name			= string(formatName) + "_" + filterName;
1357 				Texture2DArrayTestCaseParameters	testParameters;
1358 
1359 				testParameters.format		= filterableFormatsByType[fmtNdx].format;
1360 				testParameters.minFilter	= minFilter;
1361 				testParameters.magFilter	= isMipmap ? Sampler::LINEAR : minFilter;
1362 
1363 				testParameters.wrapS		= Sampler::REPEAT_GL;
1364 				testParameters.wrapT		= Sampler::REPEAT_GL;
1365 				testParameters.width		= 128;
1366 				testParameters.height		= 128;
1367 				testParameters.numLayers	= 8;
1368 
1369 				testParameters.programs.push_back(PROGRAM_2D_ARRAY_FLOAT);
1370 				testParameters.programs.push_back(PROGRAM_2D_ARRAY_UINT);
1371 
1372 				// Some tests have to be skipped due to the restrictions of the verifiers.
1373 				if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1374 				{
1375 					filterGroup->addChild(new TextureTestCase<Texture2DArrayFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1376 				}
1377 			}
1378 			formatsGroup->addChild(filterGroup.release());
1379 		}
1380 
1381 		// Sizes.
1382 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2DArray); sizeNdx++)
1383 		{
1384 			const string					filterGroupName = de::toString(sizes2DArray[sizeNdx].width) + "x" + de::toString(sizes2DArray[sizeNdx].height) + "x" + de::toString(sizes2DArray[sizeNdx].numLayers);
1385 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1386 
1387 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1388 			{
1389 				const Sampler::FilterMode			minFilter		= minFilterModes[filterNdx].mode;
1390 				const char* const					filterName		= minFilterModes[filterNdx].name;
1391 				const bool							isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1392 				const string						name			= filterName;
1393 				Texture2DArrayTestCaseParameters	testParameters;
1394 
1395 				testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1396 				testParameters.minFilter	= minFilter;
1397 				testParameters.magFilter	= isMipmap ? Sampler::LINEAR : minFilter;
1398 				testParameters.wrapS		= Sampler::REPEAT_GL;
1399 				testParameters.wrapT		= Sampler::REPEAT_GL;
1400 				testParameters.width		= sizes2DArray[sizeNdx].width;
1401 				testParameters.height		= sizes2DArray[sizeNdx].height;
1402 				testParameters.numLayers	= sizes2DArray[sizeNdx].numLayers;
1403 
1404 				testParameters.programs.push_back(PROGRAM_2D_ARRAY_FLOAT);
1405 
1406 				filterGroup->addChild(new TextureTestCase<Texture2DArrayFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1407 			}
1408 			sizesGroup->addChild(filterGroup.release());
1409 		}
1410 
1411 		// Wrap modes.
1412 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1413 		{
1414 			de::MovePtr<tcu::TestCaseGroup>	minFilterGroup(new tcu::TestCaseGroup(testCtx, minFilterModes[minFilterNdx].name, ""));
1415 
1416 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1417 			{
1418 				de::MovePtr<tcu::TestCaseGroup>	magFilterGroup(new tcu::TestCaseGroup(testCtx, magFilterModes[magFilterNdx].name, ""));
1419 
1420 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1421 				{
1422 					de::MovePtr<tcu::TestCaseGroup>	wrapSGroup(new tcu::TestCaseGroup(testCtx, wrapModes[wrapSNdx].name, ""));
1423 
1424 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1425 					{
1426 						const string						name			= wrapModes[wrapTNdx].name;
1427 						Texture2DArrayTestCaseParameters	testParameters;
1428 
1429 						testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1430 						testParameters.minFilter	= minFilterModes[minFilterNdx].mode;
1431 						testParameters.magFilter	= magFilterModes[magFilterNdx].mode;
1432 						testParameters.wrapS		= wrapModes[wrapSNdx].mode;
1433 						testParameters.wrapT		= wrapModes[wrapTNdx].mode;
1434 						testParameters.width		= 123;
1435 						testParameters.height		= 107;
1436 						testParameters.numLayers	= 7;
1437 
1438 						testParameters.programs.push_back(PROGRAM_2D_ARRAY_FLOAT);
1439 
1440 						wrapSGroup->addChild(new TextureTestCase<Texture2DArrayFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1441 					}
1442 					magFilterGroup->addChild(wrapSGroup.release());
1443 				}
1444 				minFilterGroup->addChild(magFilterGroup.release());
1445 			}
1446 			combinationsGroup->addChild(minFilterGroup.release());
1447 		}
1448 
1449 		group2DArray->addChild(formatsGroup.release());
1450 		group2DArray->addChild(sizesGroup.release());
1451 		group2DArray->addChild(combinationsGroup.release());
1452 
1453 		textureFilteringTests->addChild(group2DArray.release());
1454 	}
1455 
1456 	// 3D texture filtering.
1457 	{
1458 		de::MovePtr<tcu::TestCaseGroup>	group3D				(new tcu::TestCaseGroup(testCtx, "3d", "3D Texture Filtering"));
1459 
1460 		de::MovePtr<tcu::TestCaseGroup>	formatsGroup		(new tcu::TestCaseGroup(testCtx, "formats", "3D Texture Formats"));
1461 		de::MovePtr<tcu::TestCaseGroup>	sizesGroup			(new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1462 		de::MovePtr<tcu::TestCaseGroup>	combinationsGroup	(new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1463 
1464 		// Formats.
1465 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1466 		{
1467 			const string					filterGroupName = filterableFormatsByType[fmtNdx].name;
1468 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1469 
1470 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1471 			{
1472 				const Sampler::FilterMode	minFilter		= minFilterModes[filterNdx].mode;
1473 				const char* const			filterName		= minFilterModes[filterNdx].name;
1474 				const bool					isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1475 				const char* const			formatName		= filterableFormatsByType[fmtNdx].name;
1476 				const string				name			= string(formatName) + "_" + filterName;
1477 				Texture3DTestCaseParameters	testParameters;
1478 
1479 				testParameters.format		= filterableFormatsByType[fmtNdx].format;
1480 				testParameters.minFilter	= minFilter;
1481 				testParameters.magFilter	= isMipmap ? Sampler::LINEAR : minFilter;
1482 
1483 				testParameters.wrapS		= Sampler::REPEAT_GL;
1484 				testParameters.wrapT		= Sampler::REPEAT_GL;
1485 				testParameters.wrapR		= Sampler::REPEAT_GL;
1486 				testParameters.width		= 64;
1487 				testParameters.height		= 64;
1488 				testParameters.depth		= 64;
1489 
1490 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
1491 				testParameters.programs.push_back(PROGRAM_3D_UINT);
1492 
1493 				// Some tests have to be skipped due to the restrictions of the verifiers.
1494 				if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1495 				{
1496 					filterGroup->addChild(new TextureTestCase<Texture3DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1497 				}
1498 			}
1499 			formatsGroup->addChild(filterGroup.release());
1500 		}
1501 
1502 		// Sizes.
1503 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes3D); sizeNdx++)
1504 		{
1505 			const string					filterGroupName = de::toString(sizes3D[sizeNdx].width) + "x" + de::toString(sizes3D[sizeNdx].height) + "x" + de::toString(sizes3D[sizeNdx].depth);
1506 			de::MovePtr<tcu::TestCaseGroup>	filterGroup		(new tcu::TestCaseGroup(testCtx, filterGroupName.c_str(), ""));
1507 
1508 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1509 			{
1510 				const Sampler::FilterMode		minFilter		= minFilterModes[filterNdx].mode;
1511 				const char* const				filterName		= minFilterModes[filterNdx].name;
1512 				const bool						isMipmap		= minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1513 				const string					name			= filterName;
1514 				Texture3DTestCaseParameters		testParameters;
1515 
1516 				testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1517 				testParameters.minFilter	= minFilter;
1518 				testParameters.magFilter	= isMipmap ? Sampler::LINEAR : minFilter;
1519 				testParameters.wrapS		= Sampler::REPEAT_GL;
1520 				testParameters.wrapT		= Sampler::REPEAT_GL;
1521 				testParameters.wrapR		= Sampler::REPEAT_GL;
1522 				testParameters.width		= sizes3D[sizeNdx].width;
1523 				testParameters.height		= sizes3D[sizeNdx].height;
1524 				testParameters.depth		= sizes3D[sizeNdx].depth;
1525 
1526 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
1527 
1528 				filterGroup->addChild(new TextureTestCase<Texture3DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1529 			}
1530 			sizesGroup->addChild(filterGroup.release());
1531 		}
1532 
1533 		// Wrap modes.
1534 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1535 		{
1536 			de::MovePtr<tcu::TestCaseGroup>	minFilterGroup(new tcu::TestCaseGroup(testCtx, minFilterModes[minFilterNdx].name, ""));
1537 
1538 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1539 			{
1540 				de::MovePtr<tcu::TestCaseGroup>	magFilterGroup(new tcu::TestCaseGroup(testCtx, magFilterModes[magFilterNdx].name, ""));
1541 
1542 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1543 				{
1544 					de::MovePtr<tcu::TestCaseGroup>	wrapSGroup(new tcu::TestCaseGroup(testCtx, wrapModes[wrapSNdx].name, ""));
1545 
1546 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1547 					{
1548 						de::MovePtr<tcu::TestCaseGroup>	wrapTGroup(new tcu::TestCaseGroup(testCtx, wrapModes[wrapTNdx].name, ""));
1549 
1550 						for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++)
1551 						{
1552 							const string				name			= wrapModes[wrapRNdx].name;
1553 							Texture3DTestCaseParameters	testParameters;
1554 
1555 							testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM;
1556 							testParameters.minFilter	= minFilterModes[minFilterNdx].mode;
1557 							testParameters.magFilter	= magFilterModes[magFilterNdx].mode;
1558 							testParameters.wrapS		= wrapModes[wrapSNdx].mode;
1559 							testParameters.wrapT		= wrapModes[wrapTNdx].mode;
1560 							testParameters.wrapR		= wrapModes[wrapRNdx].mode;
1561 							testParameters.width		= 63;
1562 							testParameters.height		= 57;
1563 							testParameters.depth		= 67;
1564 
1565 							testParameters.programs.push_back(PROGRAM_3D_FLOAT);
1566 
1567 							wrapTGroup->addChild(new TextureTestCase<Texture3DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1568 						}
1569 						wrapSGroup->addChild(wrapTGroup.release());
1570 					}
1571 					magFilterGroup->addChild(wrapSGroup.release());
1572 				}
1573 				minFilterGroup->addChild(magFilterGroup.release());
1574 			}
1575 			combinationsGroup->addChild(minFilterGroup.release());
1576 		}
1577 
1578 		group3D->addChild(formatsGroup.release());
1579 		group3D->addChild(sizesGroup.release());
1580 		group3D->addChild(combinationsGroup.release());
1581 
1582 		textureFilteringTests->addChild(group3D.release());
1583 	}
1584 }
1585 
1586 } // anonymous
1587 
createTextureFilteringTests(tcu::TestContext & testCtx)1588 tcu::TestCaseGroup*	createTextureFilteringTests	(tcu::TestContext& testCtx)
1589 {
1590 	return createTestGroup(testCtx, "filtering", "Texture filtering tests.", populateTextureFilteringTests);
1591 }
1592 
1593 } // texture
1594 } // vkt
1595