1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
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 Texture filtering anisotropy tests
22 *//*--------------------------------------------------------------------*/
23
24#include "vktTextureFilteringAnisotropyTests.hpp"
25
26#include "vktTextureTestUtil.hpp"
27#include "vkImageUtil.hpp"
28#include "vkQueryUtil.hpp"
29#include "tcuImageCompare.hpp"
30#include <vector>
31
32using namespace vk;
33
34namespace vkt
35{
36namespace texture
37{
38
39using std::string;
40using std::vector;
41using std::max;
42using std::min;
43using tcu::Vec2;
44using tcu::Vec4;
45using tcu::Sampler;
46using tcu::Surface;
47using tcu::TextureFormat;
48using namespace texture::util;
49using namespace glu::TextureTestUtil;
50
51namespace
52{
53static const deUint32 ANISOTROPY_TEST_RESOLUTION = 128u;
54
55struct AnisotropyParams : public ReferenceParams
56{
57	AnisotropyParams	(const TextureType			texType_,
58						 const float				maxAnisotropy_,
59						 const Sampler::FilterMode	minFilter_,
60						 const Sampler::FilterMode	magFilter_,
61						 const bool					mipMap_ = false)
62		: ReferenceParams	(texType_)
63		, maxAnisotropy		(maxAnisotropy_)
64		, minFilter			(minFilter_)
65		, magFilter			(magFilter_)
66		, mipMap			(mipMap_)
67	{
68	}
69
70	float				maxAnisotropy;
71	Sampler::FilterMode	minFilter;
72	Sampler::FilterMode	magFilter;
73	bool				mipMap;
74};
75
76class FilteringAnisotropyInstance : public vkt::TestInstance
77{
78public:
79	FilteringAnisotropyInstance	(Context& context, const AnisotropyParams& refParams)
80		: vkt::TestInstance	(context)
81		, m_refParams		(refParams)
82	{
83		// Sampling parameters.
84		m_refParams.sampler			= util::createSampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, m_refParams.minFilter, m_refParams.magFilter);
85		m_refParams.samplerType		= getSamplerType(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
86		m_refParams.flags			= 0u;
87		m_refParams.lodMode			= LODMODE_EXACT;
88		m_refParams.maxAnisotropy	= min(getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits.maxSamplerAnisotropy, m_refParams.maxAnisotropy);
89
90		if (m_refParams.mipMap)
91		{
92			m_refParams.maxLevel	= deLog2Floor32(ANISOTROPY_TEST_RESOLUTION);
93			m_refParams.minLod		= 0.0f;
94			m_refParams.maxLod		= static_cast<float>(m_refParams.maxLevel);
95		}
96		else
97			m_refParams.maxLevel	= 0;
98	}
99
100	tcu::TestStatus	iterate	(void)
101	{
102		// Check device for anisotropic filtering support
103		if (!m_context.getDeviceFeatures().samplerAnisotropy)
104			TCU_THROW(NotSupportedError, "Skipping anisotropic tests since the device does not support anisotropic filtering.");
105
106		TextureRenderer	renderer	(m_context, VK_SAMPLE_COUNT_1_BIT, ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
107		TestTexture2DSp	texture		= TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION));
108
109		for (int levelNdx = 0; levelNdx < m_refParams.maxLevel + 1; levelNdx++)
110		{
111			const int gridSize = max(texture->getLevel(levelNdx, 0).getHeight() / 8, 1);
112			tcu::fillWithGrid(texture->getLevel(levelNdx, 0), gridSize, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4(1.0f));
113		}
114
115		renderer.setViewport(0.0f, 0.0f, static_cast<float>(ANISOTROPY_TEST_RESOLUTION), static_cast<float>(ANISOTROPY_TEST_RESOLUTION));
116		renderer.add2DTexture(texture);
117
118		{
119			Surface			renderedFrame			(ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
120			Surface			renderedAnisotropyFrame	(ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
121			const float		position[]				=
122			{
123				-3.5f, -1.0f, 0.0f, 3.5f,
124				-3.5f, +1.0f, 0.0f, 1.0f,
125				+3.5f, -1.0f, 0.0f, 3.5f,
126				+3.5f, +1.0f, 0.0f, 1.0f
127			};
128			vector<float>	texCoord;
129
130			computeQuadTexCoord2D(texCoord, Vec2(0.0f), Vec2(1.0f));
131
132			renderer.renderQuad(renderedFrame,				position, 0, &texCoord[0], m_refParams, 1.0f);
133			renderer.renderQuad(renderedAnisotropyFrame,	position, 0, &texCoord[0], m_refParams, m_refParams.maxAnisotropy);
134
135			if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Expecting comparison to pass", "Expecting comparison to pass",
136					renderedFrame.getAccess(), renderedAnisotropyFrame.getAccess(), 0.05f, tcu::COMPARE_LOG_RESULT))
137				return tcu::TestStatus::fail("Fail");
138
139			// Anisotropic filtering is implementation dependent. Expecting differences with minification/magnification filter set to NEAREST is too strict.
140			if (m_refParams.minFilter != tcu::Sampler::NEAREST && m_refParams.magFilter != tcu::Sampler::NEAREST)
141			{
142				if (floatThresholdCompare (m_context.getTestContext().getLog(), "Expecting comparison to fail", "Expecting comparison to fail",
143							   renderedFrame.getAccess(), renderedAnisotropyFrame.getAccess(), Vec4(0.05f), tcu::COMPARE_LOG_RESULT))
144					return tcu::TestStatus::fail("Fail");
145			}
146		}
147		return tcu::TestStatus::pass("Pass");
148	}
149
150private:
151	 AnisotropyParams m_refParams;
152};
153
154class FilteringAnisotropyTests : public vkt::TestCase
155{
156public:
157					FilteringAnisotropyTests	(tcu::TestContext&			testCtx,
158												 const string&				name,
159												 const string&				description,
160												 const AnisotropyParams&	refParams)
161		: vkt::TestCase		(testCtx, name, description)
162		, m_refParams		(refParams)
163	{
164	}
165
166	void			initPrograms				(SourceCollections&	programCollection) const
167	{
168		std::vector<util::Program>	programs;
169		programs.push_back(util::PROGRAM_2D_FLOAT);
170		initializePrograms(programCollection,glu::PRECISION_HIGHP, programs);
171	}
172
173	TestInstance*	createInstance				(Context&	context) const
174	{
175		return new FilteringAnisotropyInstance(context, m_refParams);
176	}
177private :
178	const AnisotropyParams	m_refParams;
179};
180
181} // anonymous
182
183tcu::TestCaseGroup* createFilteringAnisotropyTests (tcu::TestContext& testCtx)
184{
185	de::MovePtr<tcu::TestCaseGroup>	filteringAnisotropyTests	(new tcu::TestCaseGroup(testCtx,	"filtering_anisotropy",	"Filtering anisotropy tests"));
186	de::MovePtr<tcu::TestCaseGroup>	basicTests					(new tcu::TestCaseGroup(testCtx, "basic", "Filtering anisotropy tests"));
187	de::MovePtr<tcu::TestCaseGroup>	mipmapTests					(new tcu::TestCaseGroup(testCtx, "mipmap", "Filtering anisotropy tests"));
188	const char*						valueName[]					=
189	{
190		"anisotropy_2",
191		"anisotropy_4",
192		"anisotropy_8",
193		"anisotropy_max"
194	};
195	const float						maxAnisotropy[]				=
196	{
197		2.0f,
198		4.0f,
199		8.0f,
200		10000.0f	//too huge will be flated to max value
201	};
202	const char*						magFilterName[]				=
203	{
204		"nearest",
205		"linear"
206	};
207	const tcu::Sampler::FilterMode	magFilters[]				=
208	{
209		Sampler::NEAREST,
210		Sampler::LINEAR
211	};
212
213	{
214		const tcu::Sampler::FilterMode*	minFilters		= magFilters;
215		const char**					minFilterName	= magFilterName;
216
217		for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
218		{
219			de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
220
221			for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); minFilterNdx++)
222			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
223			{
224				AnisotropyParams	refParams	(TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx]);
225				levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
226														"mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
227														"Texture filtering anisotropy basic tests", refParams));
228			}
229			basicTests->addChild(levelAnisotropyGroups.release());
230		}
231		filteringAnisotropyTests->addChild(basicTests.release());
232	}
233
234	{
235		const tcu::Sampler::FilterMode		minFilters[]	=
236		{
237			Sampler::NEAREST_MIPMAP_NEAREST,
238			Sampler::NEAREST_MIPMAP_LINEAR,
239			Sampler::LINEAR_MIPMAP_NEAREST,
240			Sampler::LINEAR_MIPMAP_LINEAR
241		};
242		const char*							minFilterName[]	=
243		{
244			"nearest_mipmap_nearest",
245			"nearest_mipmap_linear",
246			"linear_mipmap_nearest",
247			"linear_mipmap_linear"
248		};
249
250		for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
251		{
252			de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
253
254			for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++)
255			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
256			{
257				AnisotropyParams	refParams	(TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx], true);
258				levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
259														"mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
260														"Texture filtering anisotropy basic tests", refParams));
261			}
262			mipmapTests->addChild(levelAnisotropyGroups.release());
263		}
264		filteringAnisotropyTests->addChild(mipmapTests.release());
265	}
266
267	return filteringAnisotropyTests.release();
268}
269
270} // texture
271} // vkt
272