Home | History | Annotate | Download | only in texture
      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