From ad89e118084d08fa1f14ad5801b996c62eb113cc Mon Sep 17 00:00:00 2001 From: James Fitzpatrick Date: Mon, 20 Jan 2020 09:02:24 +0000 Subject: [PATCH] Correctly handle normalized formats in FloatFormat For the texture explict lod tests normalized values were treated as 8 bit floating point formats when calculating the reference interval. This ignores the fact that normalized formats are encoded as 1 / N, where N is an integer, this results in the rounding used in tests not being able to accurately round normalized formats. This incorrect rounding causes the acceptable ranges to be significantly smaller than other formats and extremely asymetric around the ideal filtered value for certain samples. Affects: dEQP-VK.texture.explicit_lod.* Components: Vulkan VK-GL-CTS issue: 2189 Change-Id: Ia4f3adefab4bfb5d9c91bd7033199b0e107179d5 --- .../modules/vulkan/texture/vktSampleVerifier.cpp | 36 ++++++------- .../modules/vulkan/texture/vktSampleVerifier.hpp | 35 +++++++------ .../vulkan/texture/vktSampleVerifierUtil.cpp | 61 +++++++++++----------- .../vulkan/texture/vktSampleVerifierUtil.hpp | 10 ++-- .../vktTextureFilteringExplicitLodTests.cpp | 40 +++++++------- framework/common/tcuFloatFormat.cpp | 36 +++++++++++++ framework/common/tcuFloatFormat.hpp | 19 +++++-- 7 files changed, 146 insertions(+), 91 deletions(-) diff --git a/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.cpp b/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.cpp index fa77507..2fb2d5f 100644 --- a/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.cpp +++ b/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.cpp @@ -62,14 +62,14 @@ int calcUnnormalizedDim (const ImgDim dim) } // anonymous -SampleVerifier::SampleVerifier (const ImageViewParameters& imParams, - const SamplerParameters& samplerParams, - const SampleLookupSettings& sampleLookupSettings, - int coordBits, - int mipmapBits, - const std::vector& conversionPrecision, - const std::vector& filteringPrecision, - const std::vector& levels) +SampleVerifier::SampleVerifier (const ImageViewParameters& imParams, + const SamplerParameters& samplerParams, + const SampleLookupSettings& sampleLookupSettings, + int coordBits, + int mipmapBits, + const std::vector>& conversionPrecision, + const std::vector>& filteringPrecision, + const std::vector& levels) : m_imParams (imParams) , m_samplerParams (samplerParams) , m_sampleLookupSettings (sampleLookupSettings) @@ -308,10 +308,10 @@ void SampleVerifier::getFilteredSample1D (const IVec3& texelBase, for (int i = 0; i < 2; ++i) { - const Interval weightInterval = m_filteringPrecision[compNdx].roundOut(Interval(i == 0 ? 1.0f - weight : weight), false); + const Interval weightInterval = m_filteringPrecision[compNdx]->roundOut(Interval(i == 0 ? 1.0f - weight : weight), false); const Interval texelInterval (false, texelsMin[i][compNdx], texelsMax[i][compNdx]); - resultInterval = m_filteringPrecision[compNdx].roundOut(resultInterval + weightInterval * texelInterval, false); + resultInterval = m_filteringPrecision[compNdx]->roundOut(resultInterval + weightInterval * texelInterval, false); } resultMin[compNdx] = (float)resultInterval.lo(); @@ -343,14 +343,14 @@ void SampleVerifier::getFilteredSample2D (const IVec3& texelBase, for (int i = 0; i < 2; ++i) { - const Interval iWeightInterval = m_filteringPrecision[compNdx].roundOut(Interval(i == 0 ? 1.0f - weights[1] : weights[1]), false); + const Interval iWeightInterval = m_filteringPrecision[compNdx]->roundOut(Interval(i == 0 ? 1.0f - weights[1] : weights[1]), false); for (int j = 0; j < 2; ++j) { - const Interval jWeightInterval = m_filteringPrecision[compNdx].roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[0] : weights[0]), false); + const Interval jWeightInterval = m_filteringPrecision[compNdx]->roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[0] : weights[0]), false); const Interval texelInterval(false, texelsMin[2 * i + j][compNdx], texelsMax[2 * i + j][compNdx]); - resultInterval = m_filteringPrecision[compNdx].roundOut(resultInterval + jWeightInterval * texelInterval, false); + resultInterval = m_filteringPrecision[compNdx]->roundOut(resultInterval + jWeightInterval * texelInterval, false); } } @@ -386,19 +386,19 @@ void SampleVerifier::getFilteredSample3D (const IVec3& texelBase, for (int i = 0; i < 2; ++i) { - const Interval iWeightInterval = m_filteringPrecision[compNdx].roundOut(Interval(i == 0 ? 1.0f - weights[2] : weights[2]), false); + const Interval iWeightInterval = m_filteringPrecision[compNdx]->roundOut(Interval(i == 0 ? 1.0f - weights[2] : weights[2]), false); for (int j = 0; j < 2; ++j) { - const Interval jWeightInterval = m_filteringPrecision[compNdx].roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[1] : weights[1]), false); + const Interval jWeightInterval = m_filteringPrecision[compNdx]->roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[1] : weights[1]), false); for (int k = 0; k < 2; ++k) { - const Interval kWeightInterval = m_filteringPrecision[compNdx].roundOut(jWeightInterval * Interval(k == 0 ? 1.0f - weights[0] : weights[0]), false); + const Interval kWeightInterval = m_filteringPrecision[compNdx]->roundOut(jWeightInterval * Interval(k == 0 ? 1.0f - weights[0] : weights[0]), false); const Interval texelInterval(false, texelsMin[4 * i + 2 * j + k][compNdx], texelsMax[4 * i + 2 * j + k][compNdx]); - resultInterval = m_filteringPrecision[compNdx].roundOut(resultInterval + kWeightInterval * texelInterval, false); + resultInterval = m_filteringPrecision[compNdx]->roundOut(resultInterval + kWeightInterval * texelInterval, false); } } } @@ -542,7 +542,7 @@ bool SampleVerifier::verifySampleFiltered (const Vec4& result, const Interval idealSampleHi(false, idealSampleHiMin[compNdx], idealSampleHiMax[compNdx]); const Interval idealSample - = m_filteringPrecision[compNdx].roundOut(Interval(weight) * idealSampleLo + Interval(1.0f - weight) * idealSampleHi, false); + = m_filteringPrecision[compNdx]->roundOut(Interval(weight) * idealSampleLo + Interval(1.0f - weight) * idealSampleHi, false); idealSampleMin[compNdx] = (float)idealSample.lo(); idealSampleMax[compNdx] = (float)idealSample.hi(); diff --git a/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.hpp b/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.hpp index 2a3cc2f..1d59665 100644 --- a/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.hpp +++ b/external/vulkancts/modules/vulkan/texture/vktSampleVerifier.hpp @@ -26,6 +26,7 @@ #include "vkDefs.hpp" #include "deUniquePtr.hpp" +#include "deSharedPtr.hpp" #include "tcuFloatFormat.hpp" #include "tcuTexture.hpp" @@ -122,14 +123,14 @@ struct ImageViewParameters class SampleVerifier { public: - SampleVerifier (const ImageViewParameters& imParams, - const SamplerParameters& samplerParams, - const SampleLookupSettings& sampleLookupSettings, - int coordBits, - int mipmapBits, - const std::vector& conversionPrecision, - const std::vector& filteringPrecision, - const std::vector& levels); + SampleVerifier (const ImageViewParameters& imParams, + const SamplerParameters& samplerParams, + const SampleLookupSettings& sampleLookupSettings, + int coordBits, + int mipmapBits, + const std::vector>& conversionPrecision, + const std::vector>& filteringPrecision, + const std::vector& levels); bool verifySample (const SampleArguments& args, const tcu::Vec4& result) const; @@ -229,18 +230,18 @@ private: deInt32& stepMin, deInt32& stepMax) const; - const ImageViewParameters& m_imParams; - const SamplerParameters& m_samplerParams; - const SampleLookupSettings& m_sampleLookupSettings; + const ImageViewParameters& m_imParams; + const SamplerParameters& m_samplerParams; + const SampleLookupSettings& m_sampleLookupSettings; - const int m_coordBits; - const int m_mipmapBits; - const std::vector m_conversionPrecision; - const std::vector m_filteringPrecision; + const int m_coordBits; + const int m_mipmapBits; + const std::vector> m_conversionPrecision; + const std::vector> m_filteringPrecision; - const int m_unnormalizedDim; + const int m_unnormalizedDim; - const std::vector& m_levels; + const std::vector& m_levels; }; } // texture diff --git a/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp b/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp index 1b0d9d5..6e71e1d 100644 --- a/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp +++ b/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp @@ -615,24 +615,24 @@ deInt64 signExtend (deUint64 src, int bits) return (deInt64) src; } -void convertFP16 (const void* fp16Ptr, - FloatFormat internalFormat, - float& resultMin, - float& resultMax) +void convertFP16 (const void* fp16Ptr, + const de::SharedPtr& internalFormat, + float& resultMin, + float& resultMax) { const Float16 fp16(*(const deUint16*) fp16Ptr); - const Interval fpInterval = internalFormat.roundOut(Interval(fp16.asDouble()), false); + const Interval fpInterval = internalFormat->roundOut(Interval(fp16.asDouble()), false); resultMin = (float) fpInterval.lo(); resultMax = (float) fpInterval.hi(); } -void convertNormalizedInt (deInt64 num, - int numBits, - bool isSigned, - FloatFormat internalFormat, - float& resultMin, - float& resultMax) +void convertNormalizedInt (deInt64 num, + int numBits, + bool isSigned, + const de::SharedPtr& internalFormat, + float& resultMin, + float& resultMax) { DE_ASSERT(numBits > 0); @@ -643,9 +643,10 @@ void convertNormalizedInt (deInt64 num, --exp; const double div = (double) (((deUint64) 1 << exp) - 1); + const double value = de::max(c / div, -1.0); - Interval resultInterval(de::max(c / div, -1.0)); - resultInterval = internalFormat.roundOut(resultInterval, false); + Interval resultInterval(value - internalFormat->ulp(value), value + internalFormat->ulp(value)); + resultInterval = internalFormat->roundOut(resultInterval, false); resultMin = (float) resultInterval.lo(); resultMax = (float) resultInterval.hi(); @@ -773,11 +774,11 @@ deUint64 readChannel (const void* ptr, return result; } -void convertNormalizedFormat (const void* pixelPtr, - TextureFormat texFormat, - const std::vector& internalFormat, - Vec4& resultMin, - Vec4& resultMax) +void convertNormalizedFormat (const void* pixelPtr, + TextureFormat texFormat, + const std::vector>& internalFormat, + Vec4& resultMin, + Vec4& resultMax) { TextureSwizzle readSwizzle = getChannelReadSwizzle(texFormat.order); const TextureChannelClass chanClass = getTextureChannelClass(texFormat.type); @@ -900,19 +901,19 @@ void convertNormalizedFormat (const void* pixelPtr, if (chanBits == 1) { if (resultMin[compNdx] == 1.0f) - resultMin[compNdx] -= float(internalFormat[compNdx].ulp(1.0)); + resultMin[compNdx] -= float(internalFormat[compNdx]->ulp(1.0)); if (resultMax[compNdx] == 0.0f) - resultMax[compNdx] += float(internalFormat[compNdx].ulp(0.0)); + resultMax[compNdx] += float(internalFormat[compNdx]->ulp(0.0)); } } } } -void convertFloatFormat (const void* pixelPtr, - TextureFormat texFormat, - const std::vector& internalFormat, - Vec4& resultMin, - Vec4& resultMax) +void convertFloatFormat (const void* pixelPtr, + TextureFormat texFormat, + const std::vector>& internalFormat, + Vec4& resultMin, + Vec4& resultMax) { DE_ASSERT(getTextureChannelClass(texFormat.type) == TEXTURECHANNELCLASS_FLOATING_POINT); @@ -949,11 +950,11 @@ void convertFloatFormat (const void* pixelPtr, } // anonymous -void convertFormat (const void* pixelPtr, - TextureFormat texFormat, - const std::vector& internalFormat, - Vec4& resultMin, - Vec4& resultMax) +void convertFormat (const void* pixelPtr, + TextureFormat texFormat, + const std::vector>& internalFormat, + Vec4& resultMin, + Vec4& resultMax) { const TextureChannelClass chanClass = getTextureChannelClass(texFormat.type); diff --git a/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.hpp b/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.hpp index ff79359..d451197 100644 --- a/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.hpp +++ b/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.hpp @@ -99,11 +99,11 @@ void wrapCubemapCorner (const tcu::IVec2& coord, tcu::IVec2& cornerCoord1, tcu::IVec2& cornerCoord2); -void convertFormat (const void* pixelPtr, - tcu::TextureFormat texFormat, - const std::vector& internalFormat, - tcu::Vec4& resultMin, - tcu::Vec4& resultMax); +void convertFormat (const void* pixelPtr, + tcu::TextureFormat texFormat, + const std::vector>& internalFormat, + tcu::Vec4& resultMin, + tcu::Vec4& resultMax); template bool isEqualRelEpsilon (const tcu::Vector& a, const tcu::Vector& b, const float epsilon) diff --git a/external/vulkancts/modules/vulkan/texture/vktTextureFilteringExplicitLodTests.cpp b/external/vulkancts/modules/vulkan/texture/vktTextureFilteringExplicitLodTests.cpp index c839a01..cf35765 100644 --- a/external/vulkancts/modules/vulkan/texture/vktTextureFilteringExplicitLodTests.cpp +++ b/external/vulkancts/modules/vulkan/texture/vktTextureFilteringExplicitLodTests.cpp @@ -50,6 +50,7 @@ #include "deMath.h" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" +#include "deSharedPtr.hpp" #include #include @@ -67,28 +68,31 @@ using std::string; namespace { -std::vector getPrecision (VkFormat format, int fpPrecisionDelta) +std::vector> getPrecision (VkFormat format, int fpPrecisionDelta) { - std::vector floatFormats; - const tcu::FloatFormat fp16 (-14, 15, 10, false); - const tcu::FloatFormat fp32 (-126, 127, 23, true); - const tcu::TextureFormat tcuFormat = mapVkFormat(format); - const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(tcuFormat.type); - const tcu::IVec4 channelDepth = tcu::getTextureFormatBitDepth(tcuFormat); + std::vector> floatFormats; + de::SharedPtr fp16 (new tcu::FloatFormat(-14, 15, std::max(0, 10 + fpPrecisionDelta), false, tcu::YES)); + de::SharedPtr fp32 (new tcu::FloatFormat(-126, 127, std::max(0, 23 + fpPrecisionDelta), true)); + const tcu::TextureFormat tcuFormat = mapVkFormat(format); + const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(tcuFormat.type); + const tcu::IVec4 channelDepth = tcu::getTextureFormatBitDepth(tcuFormat); for (int channelIdx = 0; channelIdx < 4; channelIdx++) { switch(channelClass) { case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: + floatFormats.push_back(de::SharedPtr(new tcu::NormalizedFormat(std::max(0,channelDepth[channelIdx] + fpPrecisionDelta - 1)))); + break; + case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: - floatFormats.push_back(tcu::FloatFormat(0, 0, std::max(0,channelDepth[channelIdx] + fpPrecisionDelta), false, tcu::YES)); + floatFormats.push_back(de::SharedPtr(new tcu::NormalizedFormat(std::max(0,channelDepth[channelIdx] + fpPrecisionDelta)))); break; case TEXTURECHANNELCLASS_FLOATING_POINT: if (channelDepth[channelIdx] == 16) { - floatFormats.push_back(tcu::FloatFormat(fp16.getMinExp(), fp16.getMaxExp(), std::max(0,fp16.getFractionBits() + fpPrecisionDelta), false, tcu::YES)); + floatFormats.push_back(fp16); } else { @@ -603,15 +607,15 @@ TestStatus TextureFilteringTestInstance::verify (void) { // \todo [2016-06-24 collinbaker] Handle cubemaps - const int coordBits = (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits; - const int mipmapBits = (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits; - const int maxPrintedFailures = 5; - int failCount = 0; - int warningCount = 0; - const tcu::TextureFormat tcuFormat = mapVkFormat(m_imParams.format); - std::vector strictPrecision = getPrecision(m_imParams.format, 0); - std::vector relaxedPrecision = tcuFormat.type == tcu::TextureFormat::HALF_FLOAT ? getPrecision(m_imParams.format, -3) : getPrecision(m_imParams.format, -2); - const bool allowRelaxedPrecision = (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT || tcuFormat.type == tcu::TextureFormat::SNORM_INT8) && + const int coordBits = (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits; + const int mipmapBits = (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits; + const int maxPrintedFailures = 5; + int failCount = 0; + int warningCount = 0; + const tcu::TextureFormat tcuFormat = mapVkFormat(m_imParams.format); + std::vector> strictPrecision = getPrecision(m_imParams.format, 0); + std::vector> relaxedPrecision = tcuFormat.type == tcu::TextureFormat::HALF_FLOAT ? getPrecision(m_imParams.format, -3) : getPrecision(m_imParams.format, -2); + const bool allowRelaxedPrecision = (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT || tcuFormat.type == tcu::TextureFormat::SNORM_INT8) && (m_samplerParams.minFilter == VK_FILTER_LINEAR || m_samplerParams.magFilter == VK_FILTER_LINEAR); const SampleVerifier verifier (m_imParams, diff --git a/framework/common/tcuFloatFormat.cpp b/framework/common/tcuFloatFormat.cpp index 08254b8..16ae13c 100644 --- a/framework/common/tcuFloatFormat.cpp +++ b/framework/common/tcuFloatFormat.cpp @@ -295,6 +295,42 @@ FloatFormat FloatFormat::nativeDouble (void) return nativeFormat(); } +NormalizedFormat::NormalizedFormat (int fractionBits) + : FloatFormat(0, 0, fractionBits, true, tcu::YES) +{ + +} + +double NormalizedFormat::round(double d, bool upward) const +{ + const int fractionBits = getFractionBits(); + + if (fractionBits <= 0) + return d; + + const int maxIntValue = (1 << fractionBits) - 1; + const double value = d * maxIntValue; + const double normValue = upward ? deCeil(value) : deFloor(value); + return normValue / maxIntValue; +} + +double NormalizedFormat::ulp(double x, double count) const +{ + (void) x; + + const int maxIntValue = (1 << getFractionBits()) - 1; + const double precision = 1.0 / maxIntValue; + return precision * count; +} + +double NormalizedFormat::roundOut (double d, bool upward, bool roundUnderOverflow) const +{ + if (roundUnderOverflow && deAbs(d) > 1.0 && (upward == (d < 0.0))) + return deSign(d); + else + return round(d, upward); +} + namespace { diff --git a/framework/common/tcuFloatFormat.hpp b/framework/common/tcuFloatFormat.hpp index 66f23f6..849f85b 100644 --- a/framework/common/tcuFloatFormat.hpp +++ b/framework/common/tcuFloatFormat.hpp @@ -49,6 +49,7 @@ public: YesNoMaybe hasSubnormal = MAYBE, YesNoMaybe hasInf = MAYBE, YesNoMaybe hasNaN = MAYBE); + virtual ~FloatFormat() {} int getMinExp (void) const { return m_minExp; } int getMaxExp (void) const { return m_maxExp; } @@ -57,10 +58,10 @@ public: YesNoMaybe hasInf (void) const { return m_hasInf; } YesNoMaybe hasSubnormal (void) const { return m_hasSubnormal; } - double ulp (double x, double count = 1.0) const; + virtual double ulp (double x, double count = 1.0) const; Interval roundOut (const Interval& x, bool roundUnderOverflow) const; - double round (double d, bool upward) const; - double roundOut (double d, bool upward, bool roundUnderOverflow) const; + virtual double round (double d, bool upward) const; + virtual double roundOut (double d, bool upward, bool roundUnderOverflow) const; Interval convert (const Interval& x) const; std::string floatToHex (double x) const; @@ -83,6 +84,18 @@ private: double m_maxValue; // Largest representable finite value. } DE_WARN_UNUSED_TYPE; +class NormalizedFormat : public FloatFormat +{ +public: + NormalizedFormat (int fractionBits); + ~NormalizedFormat () {} + + double ulp (double x, double count = 1.0) const override; + double round (double d, bool upward) const override; + double roundOut (double d, bool upward, bool roundUnderOverflow) const override; + +} DE_WARN_UNUSED_TYPE; + void FloatFormat_selfTest (void); } // tcu -- 2.7.4