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