• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 using namespace vk;
33 
34 namespace vkt
35 {
36 namespace texture
37 {
38 
39 using std::string;
40 using std::vector;
41 using std::max;
42 using std::min;
43 using tcu::Vec2;
44 using tcu::Vec4;
45 using tcu::Sampler;
46 using tcu::Surface;
47 using tcu::TextureFormat;
48 using namespace texture::util;
49 using namespace glu::TextureTestUtil;
50 
51 namespace
52 {
53 static const deUint32 ANISOTROPY_TEST_RESOLUTION = 128u;
54 
55 struct AnisotropyParams : public ReferenceParams
56 {
AnisotropyParamsvkt::texture::__anond5ab04940111::AnisotropyParams57 	AnisotropyParams	(const TextureType			texType_,
58 						 const float				maxAnisotropy_,
59 						 const Sampler::FilterMode	minFilter_,
60 						 const Sampler::FilterMode	magFilter_,
61 						 const bool					singleLevelImage_ = false,
62 						 const bool					mipMap_ = false)
63 		: ReferenceParams	(texType_)
64 		, maxAnisotropy		(maxAnisotropy_)
65 		, minFilter			(minFilter_)
66 		, magFilter			(magFilter_)
67 		, singleLevelImage	(singleLevelImage_)
68 		, mipMap			(mipMap_)
69 	{
70 	}
71 
72 	float				maxAnisotropy;
73 	Sampler::FilterMode	minFilter;
74 	Sampler::FilterMode	magFilter;
75 	bool				singleLevelImage;
76 	bool				mipMap;
77 };
78 
79 class FilteringAnisotropyInstance : public vkt::TestInstance
80 {
81 public:
FilteringAnisotropyInstance(Context & context,const AnisotropyParams & refParams)82 	FilteringAnisotropyInstance	(Context& context, const AnisotropyParams& refParams)
83 		: vkt::TestInstance	(context)
84 		, m_refParams		(refParams)
85 	{
86 		// Sampling parameters.
87 		m_refParams.sampler			= util::createSampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, m_refParams.minFilter, m_refParams.magFilter);
88 		m_refParams.samplerType		= getSamplerType(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
89 		m_refParams.flags			= 0u;
90 		m_refParams.lodMode			= LODMODE_EXACT;
91 		m_refParams.maxAnisotropy	= min(getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits.maxSamplerAnisotropy, m_refParams.maxAnisotropy);
92 
93 		if (m_refParams.mipMap)
94 		{
95 			m_refParams.maxLevel	= deLog2Floor32(ANISOTROPY_TEST_RESOLUTION);
96 			m_refParams.minLod		= 0.0f;
97 			m_refParams.maxLod		= static_cast<float>(m_refParams.maxLevel);
98 		}
99 		else
100 			m_refParams.maxLevel	= 0;
101 	}
102 
iterate(void)103 	tcu::TestStatus	iterate	(void)
104 	{
105 		TextureRenderer	renderer(m_context, VK_SAMPLE_COUNT_1_BIT, ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
106 		TestTexture2DSp	texture;
107 
108 		if (m_refParams.singleLevelImage)
109 		{
110 			// Add miplevel count (1u) as parameter if we want to test anisotropic filtering on image that has a single mip level.
111 			texture				= TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION, 1u));
112 			const int gridSize	= max(texture->getLevel(0, 0).getHeight() / 8, 1);
113 			tcu::fillWithGrid(texture->getLevel(0, 0), gridSize, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4(1.0f));
114 		}
115 		else
116 		{
117 			texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION));
118 			for (int levelNdx = 0; levelNdx < m_refParams.maxLevel + 1; levelNdx++)
119 			{
120 				const int gridSize = max(texture->getLevel(levelNdx, 0).getHeight() / 8, 1);
121 				tcu::fillWithGrid(texture->getLevel(levelNdx, 0), gridSize, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4(1.0f));
122 			}
123 		}
124 
125 		renderer.setViewport(0.0f, 0.0f, static_cast<float>(ANISOTROPY_TEST_RESOLUTION), static_cast<float>(ANISOTROPY_TEST_RESOLUTION));
126 		renderer.add2DTexture(texture, VK_IMAGE_ASPECT_COLOR_BIT);
127 
128 		{
129 			Surface			renderedFrame			(ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
130 			Surface			renderedAnisotropyFrame	(ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
131 			const float		position[]				=
132 			{
133 				-3.5f, -1.0f, 0.0f, 3.5f,
134 				-3.5f, +1.0f, 0.0f, 1.0f,
135 				+3.5f, -1.0f, 0.0f, 3.5f,
136 				+3.5f, +1.0f, 0.0f, 1.0f
137 			};
138 			vector<float>	texCoord;
139 
140 			computeQuadTexCoord2D(texCoord, Vec2(0.0f), Vec2(1.0f));
141 
142 			renderer.renderQuad(renderedFrame,				position, 0, &texCoord[0], m_refParams, 1.0f);
143 			renderer.renderQuad(renderedAnisotropyFrame,	position, 0, &texCoord[0], m_refParams, m_refParams.maxAnisotropy);
144 
145 			if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Expecting comparison to pass", "Expecting comparison to pass",
146 					renderedFrame.getAccess(), renderedAnisotropyFrame.getAccess(), 0.05f, tcu::COMPARE_LOG_RESULT))
147 				return tcu::TestStatus::fail("Fail");
148 
149 			// Anisotropic filtering is implementation dependent. Expecting differences with minification/magnification filter set to NEAREST is too strict.
150 			// The specification does not require that your aniso & bi-linear filtering are different even in LINEAR, but this check is 'generally' going
151 			// to detect *some* difference and possibly be useful in catching issues where an implementation hasn't setup their filtering modes correctly.
152 			if (m_refParams.minFilter != tcu::Sampler::NEAREST && m_refParams.magFilter != tcu::Sampler::NEAREST)
153 			{
154 				if (floatThresholdCompare (m_context.getTestContext().getLog(), "Expecting comparison to fail", "Expecting comparison to fail",
155 							   renderedFrame.getAccess(), renderedAnisotropyFrame.getAccess(), Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
156 					return tcu::TestStatus::fail("Fail");
157 			}
158 		}
159 		return tcu::TestStatus::pass("Pass");
160 	}
161 
162 private:
163 	 AnisotropyParams m_refParams;
164 };
165 
166 class FilteringAnisotropyTests : public vkt::TestCase
167 {
168 public:
FilteringAnisotropyTests(tcu::TestContext & testCtx,const string & name,const string & description,const AnisotropyParams & refParams)169 					FilteringAnisotropyTests	(tcu::TestContext&			testCtx,
170 												 const string&				name,
171 												 const string&				description,
172 												 const AnisotropyParams&	refParams)
173 		: vkt::TestCase		(testCtx, name, description)
174 		, m_refParams		(refParams)
175 	{
176 	}
177 
initPrograms(SourceCollections & programCollection) const178 	void			initPrograms				(SourceCollections&	programCollection) const
179 	{
180 		std::vector<util::Program>	programs;
181 		programs.push_back(util::PROGRAM_2D_FLOAT);
182 		initializePrograms(programCollection,glu::PRECISION_HIGHP, programs);
183 	}
184 
createInstance(Context & context) const185 	TestInstance*	createInstance				(Context&	context) const
186 	{
187 		return new FilteringAnisotropyInstance(context, m_refParams);
188 	}
189 
checkSupport(Context & context) const190 	virtual void	checkSupport				(Context&	context) const
191 	{
192 		// Check device for anisotropic filtering support.
193 		if (!context.getDeviceFeatures().samplerAnisotropy)
194 			TCU_THROW(NotSupportedError, "Skipping anisotropic tests since the device does not support anisotropic filtering.");
195 	}
196 
197 private :
198 	const AnisotropyParams	m_refParams;
199 };
200 
201 } // anonymous
202 
createFilteringAnisotropyTests(tcu::TestContext & testCtx)203 tcu::TestCaseGroup* createFilteringAnisotropyTests (tcu::TestContext& testCtx)
204 {
205 	de::MovePtr<tcu::TestCaseGroup>	filteringAnisotropyTests	(new tcu::TestCaseGroup(testCtx,	"filtering_anisotropy",	"Filtering anisotropy tests"));
206 	de::MovePtr<tcu::TestCaseGroup>	basicTests					(new tcu::TestCaseGroup(testCtx,	"basic", "Filtering anisotropy tests"));
207 	de::MovePtr<tcu::TestCaseGroup>	mipmapTests					(new tcu::TestCaseGroup(testCtx,	"mipmap", "Filtering anisotropy tests"));
208 	de::MovePtr<tcu::TestCaseGroup>	singleLevelImageTests		(new tcu::TestCaseGroup(testCtx,	"single_level", "Filtering anisotropy tests"));
209 	const char*						valueName[]					=
210 	{
211 		"anisotropy_2",
212 		"anisotropy_4",
213 		"anisotropy_8",
214 		"anisotropy_max"
215 	};
216 	const float						maxAnisotropy[]				=
217 	{
218 		2.0f,
219 		4.0f,
220 		8.0f,
221 		10000.0f	//too huge will be flated to max value
222 	};
223 	const char*						magFilterName[]				=
224 	{
225 		"nearest",
226 		"linear"
227 	};
228 	const tcu::Sampler::FilterMode	magFilters[]				=
229 	{
230 		Sampler::NEAREST,
231 		Sampler::LINEAR
232 	};
233 
234 	// Basic anisotrophy filtering tests.
235 	{
236 		const tcu::Sampler::FilterMode*	minFilters		= magFilters;
237 		const char**					minFilterName	= magFilterName;
238 
239 		for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
240 		{
241 			de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
242 
243 			for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); minFilterNdx++)
244 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
245 			{
246 				AnisotropyParams	refParams	(TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx]);
247 				levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
248 																			 "mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
249 																			 "Texture filtering anisotropy basic tests", refParams));
250 			}
251 			basicTests->addChild(levelAnisotropyGroups.release());
252 		}
253 		filteringAnisotropyTests->addChild(basicTests.release());
254 	}
255 
256 
257 	// Same as basic tests but with single imagelevel.
258 	{
259 		const tcu::Sampler::FilterMode*	minFilters		= magFilters;
260 		const char**					minFilterName	= magFilterName;
261 
262 		for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
263 		{
264 			de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
265 
266 			for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); minFilterNdx++)
267 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
268 			{
269 				AnisotropyParams	refParams	(TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx], true);
270 				levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
271 																			 "mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
272 																			 "Texture filtering anisotropy basic tests", refParams));
273 			}
274 			singleLevelImageTests->addChild(levelAnisotropyGroups.release());
275 		}
276 		filteringAnisotropyTests->addChild(singleLevelImageTests.release());
277 	}
278 
279 	{
280 		const tcu::Sampler::FilterMode		minFilters[]	=
281 		{
282 			Sampler::NEAREST_MIPMAP_NEAREST,
283 			Sampler::NEAREST_MIPMAP_LINEAR,
284 			Sampler::LINEAR_MIPMAP_NEAREST,
285 			Sampler::LINEAR_MIPMAP_LINEAR
286 		};
287 		const char*							minFilterName[]	=
288 		{
289 			"nearest_mipmap_nearest",
290 			"nearest_mipmap_linear",
291 			"linear_mipmap_nearest",
292 			"linear_mipmap_linear"
293 		};
294 
295 		for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
296 		{
297 			de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
298 
299 			for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++)
300 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
301 			{
302 				AnisotropyParams	refParams	(TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx], false, true);
303 				levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
304 														"mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
305 														"Texture filtering anisotropy basic tests", refParams));
306 			}
307 			mipmapTests->addChild(levelAnisotropyGroups.release());
308 		}
309 		filteringAnisotropyTests->addChild(mipmapTests.release());
310 	}
311 
312 	return filteringAnisotropyTests.release();
313 }
314 
315 } // texture
316 } // vkt
317