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