blob: f987a811b803b3108eef090d75def87611ae6a8c [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Texture filtering anisotropy tests
*//*--------------------------------------------------------------------*/
#include "vktTextureFilteringAnisotropyTests.hpp"
#include "vktTextureTestUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "tcuImageCompare.hpp"
#include <vector>
using namespace vk;
namespace vkt
{
namespace texture
{
using std::string;
using std::vector;
using std::max;
using std::min;
using tcu::Vec2;
using tcu::Vec4;
using tcu::Sampler;
using tcu::Surface;
using tcu::TextureFormat;
using namespace texture::util;
using namespace glu::TextureTestUtil;
namespace
{
static const deUint32 ANISOTROPY_TEST_RESOLUTION = 128u;
struct AnisotropyParams : public ReferenceParams
{
AnisotropyParams (const TextureType texType_,
const float maxAnisotropy_,
const Sampler::FilterMode minFilter_,
const Sampler::FilterMode magFilter_,
const bool mipMap_ = false)
: ReferenceParams (texType_)
, maxAnisotropy (maxAnisotropy_)
, minFilter (minFilter_)
, magFilter (magFilter_)
, mipMap (mipMap_)
{
}
float maxAnisotropy;
Sampler::FilterMode minFilter;
Sampler::FilterMode magFilter;
bool mipMap;
};
class FilteringAnisotropyInstance : public vkt::TestInstance
{
public:
FilteringAnisotropyInstance (Context& context, const AnisotropyParams& refParams)
: vkt::TestInstance (context)
, m_refParams (refParams)
{
// Sampling parameters.
m_refParams.sampler = util::createSampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, m_refParams.minFilter, m_refParams.magFilter);
m_refParams.samplerType = getSamplerType(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
m_refParams.flags = 0u;
m_refParams.lodMode = LODMODE_EXACT;
m_refParams.maxAnisotropy = min(getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits.maxSamplerAnisotropy, m_refParams.maxAnisotropy);
if (m_refParams.mipMap)
{
m_refParams.maxLevel = deLog2Floor32(ANISOTROPY_TEST_RESOLUTION);
m_refParams.minLod = 0.0f;
m_refParams.maxLod = static_cast<float>(m_refParams.maxLevel);
}
else
m_refParams.maxLevel = 0;
}
tcu::TestStatus iterate (void)
{
// Check device for anisotropic filtering support
if (!m_context.getDeviceFeatures().samplerAnisotropy)
TCU_THROW(NotSupportedError, "Skipping anisotropic tests since the device does not support anisotropic filtering.");
TextureRenderer renderer (m_context, VK_SAMPLE_COUNT_1_BIT, ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
TestTexture2DSp texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION));
for (int levelNdx = 0; levelNdx < m_refParams.maxLevel + 1; levelNdx++)
{
const int gridSize = max(texture->getLevel(levelNdx, 0).getHeight() / 8, 1);
tcu::fillWithGrid(texture->getLevel(levelNdx, 0), gridSize, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4(1.0f));
}
renderer.setViewport(0.0f, 0.0f, static_cast<float>(ANISOTROPY_TEST_RESOLUTION), static_cast<float>(ANISOTROPY_TEST_RESOLUTION));
renderer.add2DTexture(texture);
{
Surface renderedFrame (ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
Surface renderedAnisotropyFrame (ANISOTROPY_TEST_RESOLUTION, ANISOTROPY_TEST_RESOLUTION);
const float position[] =
{
-3.5f, -1.0f, 0.0f, 3.5f,
-3.5f, +1.0f, 0.0f, 1.0f,
+3.5f, -1.0f, 0.0f, 3.5f,
+3.5f, +1.0f, 0.0f, 1.0f
};
vector<float> texCoord;
computeQuadTexCoord2D(texCoord, Vec2(0.0f), Vec2(1.0f));
renderer.renderQuad(renderedFrame, position, 0, &texCoord[0], m_refParams, 1.0f);
renderer.renderQuad(renderedAnisotropyFrame, position, 0, &texCoord[0], m_refParams, m_refParams.maxAnisotropy);
if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Expecting comparison to pass", "Expecting comparison to pass",
renderedFrame.getAccess(), renderedAnisotropyFrame.getAccess(), 0.05f, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("Fail");
// Anisotropic filtering is implementation dependent. Expecting differences with minification/magnification filter set to NEAREST is too strict.
if (m_refParams.minFilter != tcu::Sampler::NEAREST && m_refParams.magFilter != tcu::Sampler::NEAREST)
{
if (floatThresholdCompare (m_context.getTestContext().getLog(), "Expecting comparison to fail", "Expecting comparison to fail",
renderedFrame.getAccess(), renderedAnisotropyFrame.getAccess(), Vec4(0.05f), tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("Fail");
}
}
return tcu::TestStatus::pass("Pass");
}
private:
AnisotropyParams m_refParams;
};
class FilteringAnisotropyTests : public vkt::TestCase
{
public:
FilteringAnisotropyTests (tcu::TestContext& testCtx,
const string& name,
const string& description,
const AnisotropyParams& refParams)
: vkt::TestCase (testCtx, name, description)
, m_refParams (refParams)
{
}
void initPrograms (SourceCollections& programCollection) const
{
std::vector<util::Program> programs;
programs.push_back(util::PROGRAM_2D_FLOAT);
initializePrograms(programCollection,glu::PRECISION_HIGHP, programs);
}
TestInstance* createInstance (Context& context) const
{
return new FilteringAnisotropyInstance(context, m_refParams);
}
private :
const AnisotropyParams m_refParams;
};
} // anonymous
tcu::TestCaseGroup* createFilteringAnisotropyTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> filteringAnisotropyTests (new tcu::TestCaseGroup(testCtx, "filtering_anisotropy", "Filtering anisotropy tests"));
de::MovePtr<tcu::TestCaseGroup> basicTests (new tcu::TestCaseGroup(testCtx, "basic", "Filtering anisotropy tests"));
de::MovePtr<tcu::TestCaseGroup> mipmapTests (new tcu::TestCaseGroup(testCtx, "mipmap", "Filtering anisotropy tests"));
const char* valueName[] =
{
"anisotropy_2",
"anisotropy_4",
"anisotropy_8",
"anisotropy_max"
};
const float maxAnisotropy[] =
{
2.0f,
4.0f,
8.0f,
10000.0f //too huge will be flated to max value
};
const char* magFilterName[] =
{
"nearest",
"linear"
};
const tcu::Sampler::FilterMode magFilters[] =
{
Sampler::NEAREST,
Sampler::LINEAR
};
{
const tcu::Sampler::FilterMode* minFilters = magFilters;
const char** minFilterName = magFilterName;
for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
{
de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); minFilterNdx++)
for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
{
AnisotropyParams refParams (TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx]);
levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
"mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
"Texture filtering anisotropy basic tests", refParams));
}
basicTests->addChild(levelAnisotropyGroups.release());
}
filteringAnisotropyTests->addChild(basicTests.release());
}
{
const tcu::Sampler::FilterMode minFilters[] =
{
Sampler::NEAREST_MIPMAP_NEAREST,
Sampler::NEAREST_MIPMAP_LINEAR,
Sampler::LINEAR_MIPMAP_NEAREST,
Sampler::LINEAR_MIPMAP_LINEAR
};
const char* minFilterName[] =
{
"nearest_mipmap_nearest",
"nearest_mipmap_linear",
"linear_mipmap_nearest",
"linear_mipmap_linear"
};
for (int anisotropyNdx = 0; anisotropyNdx < DE_LENGTH_OF_ARRAY(maxAnisotropy); anisotropyNdx++)
{
de::MovePtr<tcu::TestCaseGroup> levelAnisotropyGroups (new tcu::TestCaseGroup(testCtx, valueName[anisotropyNdx], "Filtering anisotropy tests"));
for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++)
for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
{
AnisotropyParams refParams (TEXTURETYPE_2D, maxAnisotropy[anisotropyNdx] ,minFilters[minFilterNdx], magFilters[magFilterNdx], true);
levelAnisotropyGroups->addChild(new FilteringAnisotropyTests(testCtx,
"mag_" + string(magFilterName[magFilterNdx]) + "_min_" + string(minFilterName[minFilterNdx]),
"Texture filtering anisotropy basic tests", refParams));
}
mipmapTests->addChild(levelAnisotropyGroups.release());
}
filteringAnisotropyTests->addChild(mipmapTests.release());
}
return filteringAnisotropyTests.release();
}
} // texture
} // vkt