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 { 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 76 class FilteringAnisotropyInstance : public vkt::TestInstance 77 { 78 public: 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 150 private: 151 AnisotropyParams m_refParams; 152 }; 153 154 class FilteringAnisotropyTests : public vkt::TestCase 155 { 156 public: 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 } 177 private : 178 const AnisotropyParams m_refParams; 179 }; 180 181 } // anonymous 182 183 tcu::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