external/vulkancts/modules/vulkan/tessellation/vktTessellationUtil.cpp \
external/vulkancts/modules/vulkan/tessellation/vktTessellationWindingTests.cpp \
external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.cpp \
+ external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.cpp \
external/vulkancts/modules/vulkan/texture_filtering/vktTextureFilteringTests.cpp \
external/vulkancts/modules/vulkan/texture_filtering/vktTextureFilteringExplicitLodTests.cpp \
external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.cpp \
</Test>
</TestCase>
<TestCase name="formats">
- <Test name="VK_FORMAT_B4G4R4A4_UNORM_PACK16_nearest">
+ <Test name="b4g4r4a4_unorm_pack16_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B4G4R4A4_UNORM_PACK16_linear">
+ <Test name="b4g4r4a4_unorm_pack16_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R5G6B5_UNORM_PACK16_nearest">
+ <Test name="r5g6b5_unorm_pack16_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R5G6B5_UNORM_PACK16_linear">
+ <Test name="r5g6b5_unorm_pack16_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A1R5G5B5_UNORM_PACK16_nearest">
+ <Test name="a1r5g5b5_unorm_pack16_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A1R5G5B5_UNORM_PACK16_linear">
+ <Test name="a1r5g5b5_unorm_pack16_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8_UNORM_nearest">
+ <Test name="r8_unorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8_UNORM_linear">
+ <Test name="r8_unorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8_SNORM_nearest">
+ <Test name="r8_snorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8_SNORM_linear">
+ <Test name="r8_snorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8_UNORM_nearest">
+ <Test name="r8g8_unorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8_UNORM_linear">
+ <Test name="r8g8_unorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8_SNORM_nearest">
+ <Test name="r8g8_snorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8_SNORM_linear">
+ <Test name="r8g8_snorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8B8A8_UNORM_nearest">
+ <Test name="r8g8b8a8_unorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8B8A8_UNORM_linear">
+ <Test name="r8g8b8a8_unorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8B8A8_SNORM_nearest">
+ <Test name="r8g8b8a8_snorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8B8A8_SNORM_linear">
+ <Test name="r8g8b8a8_snorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8B8A8_SRGB_nearest">
+ <Test name="b8g8r8a8_unorm_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R8G8B8A8_SRGB_linear">
+ <Test name="b8g8r8a8_unorm_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B8G8R8A8_UNORM_nearest">
+ <Test name="a8b8g8r8_unorm_pack32_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B8G8R8A8_UNORM_linear">
+ <Test name="a8b8g8r8_unorm_pack32_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B8G8R8A8_SRGB_nearest">
+ <Test name="a8b8g8r8_snorm_pack32_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B8G8R8A8_SRGB_linear">
+ <Test name="a8b8g8r8_snorm_pack32_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A8B8G8R8_UNORM_PACK32_nearest">
+ <Test name="a2b10g10r10_unorm_pack32_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A8B8G8R8_UNORM_PACK32_linear">
+ <Test name="a2b10g10r10_unorm_pack32_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A8B8G8R8_SNORM_PACK32_nearest">
+ <Test name="r16_sfloat_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A8B8G8R8_SNORM_PACK32_linear">
+ <Test name="r16_sfloat_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A8B8G8R8_SRGB_PACK32_nearest">
+ <Test name="r16g16_sfloat_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A8B8G8R8_SRGB_PACK32_linear">
+ <Test name="r16g16_sfloat_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A2B10G10R10_UNORM_PACK32_nearest">
+ <Test name="r16g16b16a16_sfloat_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_A2B10G10R10_UNORM_PACK32_linear">
+ <Test name="r16g16b16a16_sfloat_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R16_SFLOAT_nearest">
+ <Test name="r32_sfloat_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R16_SFLOAT_linear">
+ <Test name="r32_sfloat_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R16G16_SFLOAT_nearest">
+ <Test name="r32g32_sfloat_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R16G16_SFLOAT_linear">
+ <Test name="r32g32_sfloat_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R16G16B16A16_SFLOAT_nearest">
+ <Test name="r32g32b32a32_sfloat_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_R16G16B16A16_SFLOAT_linear">
+ <Test name="r32g32b32a32_sfloat_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B10G11R11_UFLOAT_PACK32_nearest">
+ </TestCase>
+ <TestCase name="derivatives">
+ <Test name="nearest_nearest_mipmap_nearest">
+ <TestInstance/>
+ </Test>
+ <Test name="nearest_nearest_mipmap_linear">
+ <TestInstance/>
+ </Test>
+ <Test name="nearest_linear_mipmap_nearest">
+ <TestInstance/>
+ </Test>
+ <Test name="nearest_linear_mipmap_linear">
+ <TestInstance/>
+ </Test>
+ <Test name="linear_nearest_mipmap_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_B10G11R11_UFLOAT_PACK32_linear">
+ <Test name="linear_nearest_mipmap_linear">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_E5B9G9R9_UFLOAT_PACK32_nearest">
+ <Test name="linear_linear_mipmap_nearest">
<TestInstance/>
</Test>
- <Test name="VK_FORMAT_E5B9G9R9_UFLOAT_PACK32_linear">
+ <Test name="linear_linear_mipmap_linear">
<TestInstance/>
</Test>
</TestCase>
dEQP-VK.texture_filtering.explicit_lod.2d.sizes.128x128_linear_linear_mipmap_nearest_clamp
dEQP-VK.texture_filtering.explicit_lod.2d.sizes.128x128_linear_linear_mipmap_linear_repeat
dEQP-VK.texture_filtering.explicit_lod.2d.sizes.128x128_linear_linear_mipmap_linear_clamp
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B4G4R4A4_UNORM_PACK16_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B4G4R4A4_UNORM_PACK16_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R5G6B5_UNORM_PACK16_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R5G6B5_UNORM_PACK16_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A1R5G5B5_UNORM_PACK16_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A1R5G5B5_UNORM_PACK16_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8_UNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8_UNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8_SNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8_SNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8_UNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8_UNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8_SNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8_SNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8B8A8_UNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8B8A8_UNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8B8A8_SNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8B8A8_SNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8B8A8_SRGB_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R8G8B8A8_SRGB_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B8G8R8A8_UNORM_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B8G8R8A8_UNORM_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B8G8R8A8_SRGB_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B8G8R8A8_SRGB_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A8B8G8R8_UNORM_PACK32_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A8B8G8R8_UNORM_PACK32_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A8B8G8R8_SNORM_PACK32_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A8B8G8R8_SNORM_PACK32_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A8B8G8R8_SRGB_PACK32_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A8B8G8R8_SRGB_PACK32_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A2B10G10R10_UNORM_PACK32_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_A2B10G10R10_UNORM_PACK32_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R16_SFLOAT_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R16_SFLOAT_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R16G16_SFLOAT_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R16G16_SFLOAT_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R16G16B16A16_SFLOAT_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_R16G16B16A16_SFLOAT_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B10G11R11_UFLOAT_PACK32_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_B10G11R11_UFLOAT_PACK32_linear
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_E5B9G9R9_UFLOAT_PACK32_nearest
-dEQP-VK.texture_filtering.explicit_lod.2d.formats.VK_FORMAT_E5B9G9R9_UFLOAT_PACK32_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.b4g4r4a4_unorm_pack16_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.b4g4r4a4_unorm_pack16_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r5g6b5_unorm_pack16_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r5g6b5_unorm_pack16_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a1r5g5b5_unorm_pack16_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a1r5g5b5_unorm_pack16_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8_unorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8_unorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8_snorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8_snorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8_unorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8_unorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8_snorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8_snorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8b8a8_unorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8b8a8_unorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8b8a8_snorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r8g8b8a8_snorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.b8g8r8a8_unorm_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.b8g8r8a8_unorm_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a8b8g8r8_unorm_pack32_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a8b8g8r8_unorm_pack32_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a8b8g8r8_snorm_pack32_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a8b8g8r8_snorm_pack32_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a2b10g10r10_unorm_pack32_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.a2b10g10r10_unorm_pack32_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r16_sfloat_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r16_sfloat_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r16g16_sfloat_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r16g16_sfloat_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r16g16b16a16_sfloat_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r16g16b16a16_sfloat_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r32_sfloat_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r32_sfloat_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r32g32_sfloat_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r32g32_sfloat_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r32g32b32a32_sfloat_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.formats.r32g32b32a32_sfloat_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.nearest_nearest_mipmap_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.nearest_nearest_mipmap_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.nearest_linear_mipmap_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.nearest_linear_mipmap_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.linear_nearest_mipmap_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.linear_nearest_mipmap_linear
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.linear_linear_mipmap_nearest
+dEQP-VK.texture_filtering.explicit_lod.2d.derivatives.linear_linear_mipmap_linear
vktTextureFilteringTests.hpp
vktSampleVerifier.cpp
vktSampleVerifier.hpp
+ vktSampleVerifierUtil.cpp
+ vktSampleVerifierUtil.hpp
vktTextureFilteringExplicitLodTests.cpp
vktTextureFilteringExplicitLodTests.hpp
)
*//*--------------------------------------------------------------------*/
#include "vktSampleVerifier.hpp"
+#include "vktSampleVerifierUtil.hpp"
#include "deMath.h"
#include "tcuFloat.hpp"
using namespace vk;
using namespace tcu;
+using namespace util;
namespace
{
-bool isEqualRelEpsilon (const float a, const float b, const float epsilon)
+int calcUnnormalizedDim (const ImgDim dim)
{
- const float diff = de::abs(a - b);
-
- const float largest = de::max(de::abs(a), de::abs(b));
-
- return diff <= largest * epsilon;
-}
-
-template <int Size>
-bool isEqualRelEpsilon (const Vector<float, Size>& a, const Vector<float, Size>& b, const float epsilon)
-{
- for (deUint8 compNdx = 0; compNdx < Size; ++compNdx)
+ if (dim == IMG_DIM_1D)
{
- if (!isEqualRelEpsilon(a[compNdx], b[compNdx], epsilon))
- {
- return false;
- }
+ return 1;
}
-
- return true;
-}
-
-float calcRelEpsilon (VkFormat format, VkFilter filter, VkSamplerMipmapMode mipmapFilter)
-{
- // This should take into account the format at some point, but doesn't now
- DE_UNREF(format);
-
- // fp16 format approximates the minimum precision for internal calculations mandated by spec
- const float fp16MachineEpsilon = 0.0009765625f;
-
- // \todo [2016-07-06 collinbaker] Pick the epsilon more
- // scientifically
- float relEpsilon = fp16MachineEpsilon;
-
- if (filter == VK_FILTER_LINEAR)
- {
- relEpsilon *= 3.0f;
- }
-
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- relEpsilon *= 2.0f;
- }
-
- return relEpsilon;
-}
-
-deInt32 mod (const deInt32 a, const deInt32 n)
-{
- const deInt32 result = a % n;
-
- return (result < 0) ? result + n : result;
-}
-
-deInt32 mirror (const deInt32 n)
-{
- if (n >= 0)
+ else if (dim == IMG_DIM_2D || dim == IMG_DIM_CUBE)
{
- return n;
+ return 2;
}
else
{
- return -(1 + n);
+ return 3;
}
}
-template <int Size>
-Vector<float, Size> floor (const Vector<float, Size>& v)
-{
- Vector<float, Size> result;
-
- for (int compNdx = 0; compNdx < Size; ++compNdx)
- {
- result[compNdx] = (float)deFloor(v[compNdx]);
- }
-
- return result;
-}
-
-template <int Size>
-Vector<float, Size> ceil (const Vector<float, Size>& v)
-{
- Vector<float, Size> result;
-
- for (int compNdx = 0; compNdx < Size; ++compNdx)
- {
- result[compNdx] = (float)deCeil(v[compNdx]);
- }
-
- return result;
-}
-
-template <int Size>
-Vector<float, Size> abs (const Vector<float, Size>& v)
-{
- Vector<float, Size> result;
-
- for (int compNdx = 0; compNdx < Size; ++compNdx)
- {
- result[compNdx] = de::abs(v[compNdx]);
- }
-
- return result;
-}
-
-Vec2 computeLevelLodBounds (const Vec2& lodBounds, deUint8 level)
-{
- Vec2 levelLodBounds;
-
- if (lodBounds[0] <= 0.0f)
- {
- levelLodBounds[0] = lodBounds[0];
- }
- else
- {
- levelLodBounds[0] = de::max(lodBounds[0], (float) level);
- }
-
- levelLodBounds[1] = de::min(lodBounds[1], (float) level + 1.0f);
-
- return levelLodBounds;
-}
-
-float addUlp (float num, deInt32 ulp)
-{
- // Note: adding positive ulp always moves float away from zero
-
- tcu::Float32 f(num);
-
- DE_ASSERT(!f.isNaN() && !f.isInf());
- DE_ASSERT(num > FLT_MIN * (float) ulp || num < FLT_MIN * (float) ulp);
-
- deUint32 bits = f.bits();
- bits += ulp;
-
- return tcu::Float32(bits).asFloat();
-}
-
-deInt32 wrapTexelCoord (const deInt32 coord,
- const deUint32 size,
- const VkSamplerAddressMode wrap)
-{
- deInt32 wrappedCoord = 0;
-
- switch (wrap)
- {
- case VK_SAMPLER_ADDRESS_MODE_REPEAT:
- wrappedCoord = mod(coord, size);
- break;
- case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
- wrappedCoord = (size - 1) - mirror(mod(coord, 2 * size) - size);
- break;
- case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
- wrappedCoord = de::clamp(coord, 0, (deInt32) size - 1);
- break;
- case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER:
- wrappedCoord = de::clamp(coord, -1, (deInt32) size);
- break;
- case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
- wrappedCoord = de::clamp(mirror(coord), 0, (deInt32) size - 1);
- break;
- default:
- DE_FATAL("Invalid VkSamplerAddressMode");
- break;
- }
-
- return wrappedCoord;
-}
-
} // anonymous
SampleVerifier::SampleVerifier (const ImageViewParameters& imParams,
int coordBits,
int mipmapBits,
const std::vector<tcu::ConstPixelBufferAccess>& pba)
-
- : m_imParams (imParams)
+// \todo [2016-07-29 collinbaker] Get rid of magic numbers
+ : m_internalFormat (-14, 15, 10, true) // fp16 format
+ , m_imParams (imParams)
, m_samplerParams (samplerParams)
, m_sampleLookupSettings (sampleLookupSettings)
, m_coordBits (coordBits)
, m_mipmapBits (mipmapBits)
+ , m_unnormalizedDim (calcUnnormalizedDim(imParams.dim))
, m_pba (pba)
{
+
+}
+
+bool SampleVerifier::coordOutOfRange (const IVec3& coord, int compNdx, int level) const
+{
+ DE_ASSERT(compNdx >= 0 && compNdx < 3);
+
+ return coord[compNdx] < 0 || coord[compNdx] >= m_pba[level].getSize()[compNdx];
+}
+
+void SampleVerifier::fetchTexelWrapped (const IVec3& coord,
+ int layer,
+ int level,
+ Vec4& resultMin,
+ Vec4& resultMax) const
+{
+ const void* pixelPtr = DE_NULL;
+
if (m_imParams.dim == IMG_DIM_1D)
{
- m_unnormalizedDim = 1;
+ pixelPtr = m_pba[level].getPixelPtr(coord[0], layer, 0);
}
else if (m_imParams.dim == IMG_DIM_2D || m_imParams.dim == IMG_DIM_CUBE)
{
- m_unnormalizedDim = 2;
+ pixelPtr = m_pba[level].getPixelPtr(coord[0], coord[1], layer);
}
else
{
- m_unnormalizedDim = 3;
+ pixelPtr = m_pba[level].getPixelPtr(coord[0], coord[1], coord[2]);
}
-}
-
-bool SampleVerifier::coordOutOfRange (const IVec3& coord, int compNdx, int level) const
-{
- DE_ASSERT(compNdx >= 0 && compNdx < 3);
- return coord[compNdx] < 0 || coord[compNdx] >= m_pba[level].getSize()[compNdx];
+ convertFormat(pixelPtr, mapVkFormat(m_imParams.format), m_internalFormat, resultMin, resultMax);
}
-Vec4 SampleVerifier::fetchTexel (const IVec3& coordIn, deUint32 layer, deUint8 level, VkFilter filter) const
+void SampleVerifier::fetchTexel (const IVec3& coordIn,
+ int layer,
+ int level,
+ VkFilter filter,
+ Vec4& resultMin,
+ Vec4& resultMax) const
{
IVec3 coord = coordIn;
// Wrapping operations
+
if (m_imParams.dim == IMG_DIM_CUBE && filter == VK_FILTER_LINEAR)
{
- const deUint32 arrayLayer = layer / 6;
- deUint8 arrayFace = (deUint8) (layer % 6);
-
- // Cube map adjacent faces ordered clockwise from top
-
- // \todo [2016-07-07 collinbaker] Verify these are correct
- static const deUint8 adjacentFaces[6][4] =
- {
- {3, 5, 2, 4},
- {3, 4, 2, 5},
- {4, 0, 5, 1},
- {5, 0, 4, 1},
- {3, 0, 2, 1},
- {3, 1, 2, 0}
- };
-
- static const deUint8 adjacentEdges[6][4] =
- {
- {1, 3, 1, 1},
- {3, 3, 3, 1},
- {2, 2, 2, 2},
- {0, 0, 0, 0},
- {2, 3, 0, 1},
- {0, 3, 2, 1}
- };
-
- static const deInt8 adjacentEdgeDirs[6][4] =
- {
- {-1, +1, +1, +1},
- {+1, +1, -1, +1},
- {+1, +1, -1, -1},
- {-1, -1, +1, +1},
- {+1, +1, +1, +1},
- {-1, +1, -1, +1}
- };
-
- static const deUint8 edgeComponent[4] = {0, 1, 0, 1};
+ // If the image is a cubemap and we are using linear filtering, we do edge or corner wrapping
- static const deUint8 edgeFactors[4][2] =
- {
- {0, 0},
- {1, 0},
- {0, 1},
- {0, 0}
- };
+ const int arrayLayer = layer / 6;
+ int arrayFace = layer % 6;
if (coordOutOfRange(coord, 0, level) != coordOutOfRange(coord, 1, level))
{
- // Handle edge
-
- deUint8 edgeNdx;
-
- if (coord[1] < 0)
- {
- edgeNdx = 0;
- }
- else if (coord[0] > 0)
- {
- edgeNdx = 1;
- }
- else if (coord[1] > 0)
- {
- edgeNdx = 2;
- }
- else
- {
- edgeNdx = 3;
- }
+ // Wrap around edge
- const deUint8 adjacentEdgeNdx = adjacentEdges[arrayFace][edgeNdx];
- const IVec2 edgeFactor = IVec2(edgeFactors[adjacentEdgeNdx][0],
- edgeFactors[adjacentEdgeNdx][1]);
- const IVec2 edgeOffset = edgeFactor * (m_pba[level].getSize().swizzle(0, 1) - IVec2(1));
+ IVec2 newCoord(0);
+ int newFace = 0;
- IVec2 newCoord;
+ wrapCubemapEdge(coord.swizzle(0, 1),
+ m_pba[level].getSize().swizzle(0, 1),
+ arrayFace,
+ newCoord,
+ newFace);
- if (adjacentEdgeDirs[arrayFace][edgeNdx] > 0)
- {
- newCoord[edgeComponent[adjacentEdgeNdx]] = coord[edgeComponent[edgeNdx]];
- }
- else
- {
- newCoord[edgeComponent[adjacentEdgeNdx]] =
- m_pba[level].getSize()[edgeComponent[edgeNdx]] - coord[edgeComponent[edgeNdx]] - 1;
- }
-
- newCoord[1 - edgeComponent[adjacentEdgeNdx]] = 0;
- coord.xy() = newCoord + edgeOffset;
-
- arrayFace = adjacentFaces[arrayFace][edgeNdx];
- layer = arrayLayer * 6 + arrayFace;
+ coord.xy() = newCoord;
+ layer = arrayLayer * 6 + newFace;
}
else if (coordOutOfRange(coord, 0, level) && coordOutOfRange(coord, 1, level))
{
- // Handle corner; corners are numbered clockwise starting
- // from top left
-
- deUint8 cornerNdx;
-
- if (coord[0] < 0 && coord[1] < 0)
- {
- cornerNdx = 0;
- }
- else if (coord[0] > 0 && coord[1] < 0)
- {
- cornerNdx = 1;
- }
- else if (coord[0] > 0 && coord[1] > 0)
- {
- cornerNdx = 2;
- }
- else
- {
- cornerNdx = 3;
- }
+ // Wrap corner
- // Calculate faces and corners thereof adjacent to sampled corner
+ int faces[3] = {arrayFace, 0, 0};
+ IVec2 cornerCoords[3];
- const deUint8 cornerEdges[2] = {cornerNdx, (deUint8) ((cornerNdx + 3) % 4)};
+ wrapCubemapCorner(coord.swizzle(0, 1),
+ m_pba[level].getSize().swizzle(0, 1),
+ arrayFace,
+ faces[1],
+ faces[2],
+ cornerCoords[0],
+ cornerCoords[1],
+ cornerCoords[2]);
- const deUint8 faces[3] = {arrayFace,
- adjacentFaces[arrayFace][cornerEdges[0]],
- adjacentFaces[arrayFace][cornerEdges[1]]};
+ // \todo [2016-08-01 collinbaker] Call into fetchTexelWrapped instead
- deUint8 faceCorners[3] = {cornerNdx, 0, 0};
+ Vec4 cornerTexels[3];
- for (deUint8 edgeNdx = 0; edgeNdx < 2; ++edgeNdx)
+ for (int ndx = 0; ndx < 3; ++ndx)
{
- const deUint8 faceEdge = adjacentEdges[arrayFace][cornerEdges[edgeNdx]];
-
- bool isFlipped = (adjacentEdgeDirs[arrayFace][cornerEdges[edgeNdx]]);
-
- if ((cornerEdges[edgeNdx] > 1) != (faceEdge > 1))
- {
- isFlipped = !isFlipped;
- }
+ int cornerLayer = faces[ndx] + arrayLayer * 6;
- if (isFlipped)
+ if (isSrgb)
{
- faceCorners[edgeNdx + 1] = (deUint8) ((faceEdge + 1) % 4);
+ cornerTexels[ndx] += sRGBToLinear(m_pba[level].getPixel(cornerCoords[ndx][0], cornerCoords[ndx][1], cornerLayer));
}
else
{
- faceCorners[edgeNdx + 1] = faceEdge;
+ cornerTexels[ndx] += m_pba[level].getPixel(cornerCoords[ndx][0], cornerCoords[ndx][1], cornerLayer);
}
}
- // Compute average of corners and return
-
- Vec4 result(0.0f);
-
- for (deUint8 faceNdx = 0; faceNdx < 3; ++faceNdx)
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
{
- IVec2 cornerFactor;
+ float compMin = cornerTexels[0][compNdx];
+ float compMax = cornerTexels[0][compNdx];
- switch (faceCorners[faceNdx])
+ for (int ndx = 1; ndx < 3; ++ndx)
{
- case 0:
- cornerFactor = IVec2(0, 0);
- break;
- case 1:
- cornerFactor = IVec2(1, 0);
- break;
- case 2:
- cornerFactor = IVec2(1, 1);
- break;
- case 3:
- cornerFactor = IVec2(0, 1);
- }
-
- const IVec2 cornerCoord = cornerFactor * (m_pba[level].getSize().swizzle(0, 1) - IVec2(1));
- const deUint32 cornerLayer = arrayLayer * 6 + faces[faceNdx];
+ const float comp = cornerTexels[ndx][compNdx];
- if (isSrgb)
- {
- result += sRGBToLinear(m_pba[level].getPixel(cornerCoord[0], cornerCoord[1], cornerLayer));
- }
- else
- {
- result += m_pba[level].getPixel(cornerCoord[0], cornerCoord[1], cornerLayer);
+ compMin = de::min(comp, compMin);
+ compMax = de::max(comp, compMax);
}
- }
- result = result / 3.0f;
+ resultMin[compNdx] = compMin;
+ resultMax[compNdx] = compMax;
+ }
- return result;
+ return;
+ }
+ else
+ {
+ // If no wrapping is necessary, just do nothing
}
}
else
{
+ // Otherwise, we do normal wrapping
+
if (m_imParams.dim == IMG_DIM_CUBE)
{
wrappingModes[0] = wrappingModes[1] = wrappingModes[2] = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
}
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
{
- const deUint32 size = m_pba[level].getSize()[compNdx];
+ const int size = m_pba[level].getSize()[compNdx];
coord[compNdx] = wrapTexelCoord(coord[compNdx], size, wrappingModes[compNdx]);
}
coordOutOfRange(coord, 1, level) ||
coordOutOfRange(coord, 2, level))
{
+ // If after wrapping coordinates are still out of range, perform texel replacement
+
switch (m_samplerParams.borderColor)
{
case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
- return Vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ {
+ resultMin = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ resultMax = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ return;
+ }
case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
- return Vec4(0.0f, 0.0f, 0.0f, 1.0f);
+ {
+ resultMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
+ resultMax = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
+ return;
+ }
case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
- return Vec4(1.0f, 1.0f, 1.0f, 1.0f);
+ {
+ resultMin = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
+ resultMax = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
+ return;
+ }
default:
+ {
// \\ [2016-07-07 collinbaker] Handle
// VK_BORDER_COLOR_INT_* borders
DE_FATAL("Not implemented");
break;
+ }
}
}
else
{
- Vec4 result;
-
- if (m_imParams.dim == IMG_DIM_1D)
- {
- result = m_pba[level].getPixel(coord[0], layer, 0);
- }
- else if (m_imParams.dim == IMG_DIM_2D)
- {
- result = m_pba[level].getPixel(coord[0], coord[1], layer);
- }
- else
- {
- result = m_pba[level].getPixel(coord[0], coord[1], coord[2]);
- }
-
- // Do sRGB conversion if necessary
+ // Otherwise, actually fetch a texel
- if (isSrgb)
- {
- return sRGBToLinear(result);
- }
- else
- {
- return result;
- }
+ fetchTexelWrapped(coord, layer, level, resultMin, resultMax);
}
-
- return Vec4(0.0f);
}
-Vec4 SampleVerifier::getFilteredSample1D (const IVec3& texelBase,
+void SampleVerifier::getFilteredSample1D (const IVec3& texelBase,
float weight,
- deUint32 layer,
- deUint8 level) const
+ int layer,
+ int level,
+ Vec4& resultMin,
+ Vec4& resultMax) const
{
- Vec4 texels[2];
+ Vec4 texelsMin[2];
+ Vec4 texelsMax[2];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ fetchTexel(texelBase + IVec3(i, 0, 0), layer, level, VK_FILTER_LINEAR, texelsMin[i], texelsMax[i]);
+ }
- for (deUint8 i = 0; i < 2; ++i)
+ Interval resultIntervals[4];
+
+ for (int ndx = 0; ndx < 4; ++ndx)
{
- texels[i] = fetchTexel(texelBase + IVec3(i, 0, 0), layer, level, VK_FILTER_LINEAR);
+ resultIntervals[ndx] = Interval(0.0);
+ }
+
+ for (int i = 0; i < 2; ++i)
+ {
+ const Interval weightInterval = m_internalFormat.roundOut(Interval(i == 0 ? 1.0f - weight : weight), false);
+
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ const Interval texelInterval(false, texelsMin[i][compNdx], texelsMax[i][compNdx]);
+
+ resultIntervals[compNdx] = m_internalFormat.roundOut(resultIntervals[compNdx] + weightInterval * texelInterval, false);
+ }
}
- return (1.0f - weight) * texels[0] + weight * texels[1];
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ resultMin[compNdx] = (float)resultIntervals[compNdx].lo();
+ resultMax[compNdx] = (float)resultIntervals[compNdx].hi();
+ }
}
-Vec4 SampleVerifier::getFilteredSample2D (const IVec3& texelBase,
+void SampleVerifier::getFilteredSample2D (const IVec3& texelBase,
const Vec2& weights,
- deUint32 layer,
- deUint8 level) const
+ int layer,
+ int level,
+ Vec4& resultMin,
+ Vec4& resultMax) const
{
- Vec4 texels[4];
+ Vec4 texelsMin[4];
+ Vec4 texelsMax[4];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ for (int j = 0; j < 2; ++j)
+ {
+ fetchTexel(texelBase + IVec3(i, j, 0), layer, level, VK_FILTER_LINEAR, texelsMin[2 * j + i], texelsMax[2 * j + i]);
+ }
+ }
+
+ Interval resultIntervals[4];
+
+ for (int ndx = 0; ndx < 4; ++ndx)
+ {
+ resultIntervals[ndx] = Interval(0.0);
+ }
- for (deUint8 i = 0; i < 2; ++i)
+ for (int i = 0; i < 2; ++i)
{
- for (deUint8 j = 0; j < 2; ++j)
+ const Interval iWeightInterval = m_internalFormat.roundOut(Interval(i == 0 ? 1.0f - weights[1] : weights[1]), false);
+
+ for (int j = 0; j < 2; ++j)
{
- texels[2 * j + i] = fetchTexel(texelBase + IVec3(i, j, 0), layer, level, VK_FILTER_LINEAR);
+ const Interval jWeightInterval = m_internalFormat.roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[0] : weights[0]), false);
+
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ const Interval texelInterval(false, texelsMin[2 * i + j][compNdx], texelsMax[2 * i + j][compNdx]);
+
+ resultIntervals[compNdx] = m_internalFormat.roundOut(resultIntervals[compNdx] + jWeightInterval * texelInterval, false);
+ }
}
}
- return (1.0f - weights[0]) * (1.0f - weights[1]) * texels[0]
- + weights[0] * (1.0f - weights[1]) * texels[1]
- + (1.0f - weights[0]) * weights[1] * texels[2]
- + weights[0] * weights[1] * texels[3];
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ resultMin[compNdx] = (float)resultIntervals[compNdx].lo();
+ resultMax[compNdx] = (float)resultIntervals[compNdx].hi();
+ }
}
-Vec4 SampleVerifier::getFilteredSample3D (const IVec3& texelBase,
+void SampleVerifier::getFilteredSample3D (const IVec3& texelBase,
const Vec3& weights,
- deUint32 layer,
- deUint8 level) const
+ int layer,
+ int level,
+ Vec4& resultMin,
+ Vec4& resultMax) const
{
- Vec4 texels[8];
+ Vec4 texelsMin[8];
+ Vec4 texelsMax[8];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ for (int j = 0; j < 2; ++j)
+ {
+ for (int k = 0; k < 2; ++k)
+ {
+ fetchTexel(texelBase + IVec3(i, j, k), layer, level, VK_FILTER_LINEAR, texelsMin[4 * k + 2 * j + i], texelsMax[4 * k + 2 * j + i]);
+ }
+ }
+ }
- for (deUint8 i = 0; i < 2; ++i)
+ Interval resultIntervals[4];
+
+ for (int ndx = 0; ndx < 4; ++ndx)
+ {
+ resultIntervals[ndx] = Interval(0.0);
+ }
+
+ for (int i = 0; i < 2; ++i)
{
- for (deUint8 j = 0; j < 2; ++j)
+ const Interval iWeightInterval = m_internalFormat.roundOut(Interval(i == 0 ? 1.0f - weights[2] : weights[2]), false);
+
+ for (int j = 0; j < 2; ++j)
{
- for (deUint8 k = 0; k < 2; ++k)
+ const Interval jWeightInterval = m_internalFormat.roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[1] : weights[1]), false);
+
+ for (int k = 0; k < 2; ++k)
{
- texels[4 * k + 2 * j + i] = fetchTexel(texelBase + IVec3(i, j, k), layer, level, VK_FILTER_LINEAR);
+ const Interval kWeightInterval = m_internalFormat.roundOut(jWeightInterval * Interval(k == 0 ? 1.0f - weights[0] : weights[0]), false);
+
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ const Interval texelInterval(false, texelsMin[4 * i + 2 * j + k][compNdx], texelsMax[4 * i + 2 * j + k][compNdx]);
+
+ resultIntervals[compNdx] = m_internalFormat.roundOut(resultIntervals[compNdx] + kWeightInterval * texelInterval, false);
+ }
}
}
}
- return (1.0f - weights[0]) * (1.0f - weights[1]) * (1.0f - weights[2]) * texels[0]
- + weights[0] * (1.0f - weights[1]) * (1.0f - weights[2]) * texels[1]
- + (1.0f - weights[0]) * weights[1] * (1.0f - weights[2]) * texels[2]
- + weights[0] * weights[1] * (1.0f - weights[2]) * texels[3]
- + (1.0f - weights[0]) * (1.0f - weights[1]) * weights[2] * texels[4]
- + weights[0] * (1.0f - weights[1]) * weights[2] * texels[5]
- + (1.0f - weights[0]) * weights[1] * weights[2] * texels[6]
- + weights[0] * weights[1] * weights[3] * texels[7];
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ resultMin[compNdx] = (float)resultIntervals[compNdx].lo();
+ resultMax[compNdx] = (float)resultIntervals[compNdx].hi();
+ }
}
-Vec4 SampleVerifier::getFilteredSample (const IVec3& texelBase,
+void SampleVerifier::getFilteredSample (const IVec3& texelBase,
const Vec3& weights,
- deUint32 layer,
- deUint8 level) const
+ int layer,
+ int level,
+ Vec4& resultMin,
+ Vec4& resultMax) const
{
DE_ASSERT(layer < m_imParams.arrayLayers);
DE_ASSERT(level < m_imParams.levels);
if (m_imParams.dim == IMG_DIM_1D)
{
- return getFilteredSample1D(texelBase, weights.x(), layer, level);
+ getFilteredSample1D(texelBase, weights.x(), layer, level, resultMin, resultMax);
}
else if (m_imParams.dim == IMG_DIM_2D || m_imParams.dim == IMG_DIM_CUBE)
{
- return getFilteredSample2D(texelBase, weights.swizzle(0, 1), layer, level);
+ getFilteredSample2D(texelBase, weights.swizzle(0, 1), layer, level, resultMin, resultMax);
}
else
{
- return getFilteredSample3D(texelBase, weights, layer, level);
- }
-}
-
-void SampleVerifier::getWeightStepBounds (const Vec3& unnormalizedCoord,
- IVec3& weightStepMin,
- IVec3& weightStepMax,
- IVec3& texelBase) const
-{
- DE_ASSERT(m_coordBits < 32);
- const deUint32 coordSteps = ((deUint32) 1) << m_coordBits;
-
- for (deUint8 compNdx = 0; compNdx < m_unnormalizedDim; ++compNdx)
- {
- const float component = unnormalizedCoord[compNdx];
- double intPart;
-
- float weight = (float) modf((double) component - 0.5, &intPart);
-
- if (weight < 0.0f)
- {
- weight = 1.0f + weight;
- intPart -= 1.0;
- }
-
- texelBase[compNdx] = (deInt32) intPart;
-
- weightStepMin[compNdx] = deCeilFloatToInt32 (weight * (float) coordSteps - 1.5f);
- weightStepMax[compNdx] = deFloorFloatToInt32(weight * (float) coordSteps + 1.5f);
-
- weightStepMin[compNdx] = de::max(weightStepMin[compNdx], (deInt32) 0);
- weightStepMax[compNdx] = de::min(weightStepMax[compNdx], (deInt32) coordSteps);
+ getFilteredSample3D(texelBase, weights, layer, level, resultMin, resultMax);
}
}
deInt32& stepMax) const
{
DE_ASSERT(m_mipmapBits < 32);
- const deUint32 mipmapSteps = ((deUint32) 1) << m_mipmapBits;
+ const int mipmapSteps = ((int)1) << m_mipmapBits;
- stepMin = deFloorFloatToInt32(lodFracBounds[0] * (float) mipmapSteps);
- stepMax = deCeilFloatToInt32 (lodFracBounds[1] * (float) mipmapSteps);
+ stepMin = deFloorFloatToInt32(lodFracBounds[0] * (float)mipmapSteps);
+ stepMax = deCeilFloatToInt32 (lodFracBounds[1] * (float)mipmapSteps);
- stepMin = de::max(stepMin, (deInt32) 0);
- stepMax = de::min(stepMax, (deInt32) mipmapSteps);
+ stepMin = de::max(stepMin, (deInt32)0);
+ stepMax = de::min(stepMax, (deInt32)mipmapSteps);
}
bool SampleVerifier::verifySampleFiltered (const Vec4& result,
- const Vec3& unnormalizedCoordHi,
- const Vec3& unnormalizedCoordLo,
- deUint32 layer,
- deUint8 levelHi,
+ const IVec3& baseTexelHiIn,
+ const IVec3& baseTexelLoIn,
+ const IVec3& texelGridOffsetHiIn,
+ const IVec3& texelGridOffsetLoIn,
+ int layer,
+ int levelHi,
const Vec2& lodFracBounds,
VkFilter filter,
VkSamplerMipmapMode mipmapFilter,
DE_ASSERT(layer < m_imParams.arrayLayers);
DE_ASSERT(levelHi < m_imParams.levels);
- const float epsilon = calcRelEpsilon(m_imParams.format, filter, mipmapFilter);
+ const int coordSteps = 1 << m_coordBits;
+ const int lodSteps = 1 << m_mipmapBits;
+ const int levelLo = (levelHi < m_imParams.levels - 1) ? levelHi + 1 : levelHi;
- const deUint32 coordSteps = ((deUint32) 1) << m_coordBits;
- const deUint32 lodSteps = ((deUint32) 1) << m_mipmapBits;
+ IVec3 baseTexelHi = baseTexelHiIn;
+ IVec3 baseTexelLo = baseTexelLoIn;
+ IVec3 texelGridOffsetHi = texelGridOffsetHiIn;
+ IVec3 texelGridOffsetLo = texelGridOffsetLoIn;
+ deInt32 lodStepsMin = 0;
+ deInt32 lodStepsMax = 0;
- IVec3 texelBase[2];
- IVec3 weightStepsMin[2];
- IVec3 weightStepsMax[2];
- deInt32 lodStepsMin;
- deInt32 lodStepsMax;
+ getMipmapStepBounds(lodFracBounds, lodStepsMin, lodStepsMax);
- int levels;
- int levelLo;
+ report << "Testing at base texel " << baseTexelHi << ", " << baseTexelLo << " offset " << texelGridOffsetHi << ", " << texelGridOffsetLo << "\n";
- if (levelHi == m_imParams.levels - 1 || mipmapFilter == VK_SAMPLER_MIPMAP_MODE_NEAREST)
- {
- levels = 1;
- levelLo = levelHi;
- mipmapFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST;
- }
- else
- {
- levels = 2;
- levelLo = 1 + levelHi;
- }
+ Vec4 idealSampleHiMin;
+ Vec4 idealSampleHiMax;
+ Vec4 idealSampleLoMin;
+ Vec4 idealSampleLoMax;
- getWeightStepBounds(unnormalizedCoordHi, weightStepsMin[0], weightStepsMax[0], texelBase[0]);
+ // Get ideal samples at steps at each mipmap level
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- getWeightStepBounds(unnormalizedCoordLo, weightStepsMin[1], weightStepsMax[1], texelBase[1]);
- getMipmapStepBounds(lodFracBounds, lodStepsMin, lodStepsMax);
- }
- else
+ if (filter == VK_FILTER_LINEAR)
{
- texelBase[1] = IVec3(0);
- weightStepsMin[1] = IVec3(0);
- weightStepsMax[1] = IVec3(0);
- }
+ // Adjust texel grid coordinates for linear filtering
+ wrapTexelGridCoordLinear(baseTexelHi, texelGridOffsetHi, m_coordBits, m_imParams.dim);
- IVec3 weightSteps[2] = {weightStepsMin[0], weightStepsMin[1]};
+ if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
+ {
+ wrapTexelGridCoordLinear(baseTexelLo, texelGridOffsetLo, m_coordBits, m_imParams.dim);
+ }
- bool done = false;
+ const Vec3 roundedWeightsHi = texelGridOffsetHi.asFloat() / (float)coordSteps;
+ const Vec3 roundedWeightsLo = texelGridOffsetLo.asFloat() / (float)coordSteps;
- while (!done)
- {
- report << "Testing at base texel " << texelBase[0] << ", " << texelBase[1] << " with weight steps " << weightSteps[0] << ", " << weightSteps[1] << "\n";
+ report << "Computed weights: " << roundedWeightsHi << ", " << roundedWeightsLo << "\n";
- Vec4 idealSampleHi, idealSampleLo;
+ getFilteredSample(baseTexelHi, roundedWeightsHi, layer, levelHi, idealSampleHiMin, idealSampleHiMax);
- // Get ideal samples at steps at each mipmap level
+ report << "Ideal hi sample: " << idealSampleHiMin << " through " << idealSampleHiMax << "\n";
- if (filter == VK_FILTER_LINEAR)
+ if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
{
- Vec3 roundedWeightsHi, roundedWeightsLo;
+ getFilteredSample(baseTexelLo, roundedWeightsLo, layer, levelLo, idealSampleLoMin, idealSampleLoMax);
- roundedWeightsHi = weightSteps[0].asFloat() / (float) coordSteps;
- roundedWeightsLo = weightSteps[1].asFloat() / (float) coordSteps;
-
- report << "Computed weights: " << roundedWeightsHi << ", " << roundedWeightsLo << "\n";
-
- idealSampleHi = getFilteredSample(texelBase[0], roundedWeightsHi, layer, levelHi);
+ report << "Ideal lo sample: " << idealSampleLoMin << " through " << idealSampleLoMax << "\n";
+ }
+ }
+ else
+ {
+ fetchTexel(baseTexelHi, layer, levelHi, VK_FILTER_NEAREST, idealSampleHiMin, idealSampleHiMax);
- report << "Ideal hi sample: " << idealSampleHi << "\n";
+ report << "Ideal hi sample: " << idealSampleHiMin << " through " << idealSampleHiMax << "\n";
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- idealSampleLo = getFilteredSample(texelBase[1], roundedWeightsLo, layer, (deUint8)levelLo);
+ if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
+ {
+ fetchTexel(baseTexelLo, layer, levelLo, VK_FILTER_NEAREST, idealSampleLoMin, idealSampleLoMax);
- report << "Ideal lo sample: " << idealSampleLo << "\n";
- }
+ report << "Ideal lo sample: " << idealSampleLoMin << " through " << idealSampleLoMax << "\n";
}
- else
- {
- // \todo [2016-07-14 collinbaker] fix this because this is definitely wrong
- idealSampleHi = fetchTexel(floor(unnormalizedCoordHi).cast<deInt32>(), layer, levelHi, VK_FILTER_NEAREST);
+ }
- report << "Ideal hi sample: " << idealSampleHi << "\n";
+ // Test ideal samples based on mipmap filtering mode
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- idealSampleLo = fetchTexel(floor(unnormalizedCoordLo).cast<deInt32>(), layer, (deUint8)levelLo, VK_FILTER_NEAREST);
+ if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
+ {
+ for (deInt32 lodStep = lodStepsMin; lodStep <= lodStepsMax; ++lodStep)
+ {
+ float weight = (float)lodStep / (float)lodSteps;
- report << "Ideal lo sample: " << idealSampleLo << "\n";
- }
- }
+ report << "Testing at mipmap weight " << weight << "\n";
- // Test ideal samples based on mipmap filtering mode
+ Vec4 idealSampleMin;
+ Vec4 idealSampleMax;
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- for (deInt32 lodStep = lodStepsMin; lodStep <= lodStepsMax; ++lodStep)
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
{
- float weight = (float) lodStep / (float) lodSteps;
+ const Interval idealSampleLo(false, idealSampleLoMin[compNdx], idealSampleLoMax[compNdx]);
+ const Interval idealSampleHi(false, idealSampleHiMin[compNdx], idealSampleHiMax[compNdx]);
- report << "Testing at mipmap weight " << weight << "\n";
+ const Interval idealSample
+ = m_internalFormat.roundOut(Interval(weight) * idealSampleLo + Interval(1.0f - weight) * idealSampleHi, false);
- Vec4 idealSample = weight * idealSampleLo + (1.0f - weight) * idealSampleHi;
+ idealSampleMin[compNdx] = (float)idealSample.lo();
+ idealSampleMax[compNdx] = (float)idealSample.hi();
+ }
- report << "Ideal sample: " << idealSample << "\n";
+ report << "Ideal sample: " << idealSampleMin << " through " << idealSampleMax << "\n";
- if (isEqualRelEpsilon(idealSample, result, epsilon))
- {
- return true;
- }
- else
- {
- report << "Failed comparison\n";
- }
- }
- }
- else if (filter == VK_FILTER_LINEAR)
- {
- if (isEqualRelEpsilon(idealSampleHi, result, epsilon))
+ if (isInRange(result, idealSampleMin, idealSampleMax))
{
return true;
}
report << "Failed comparison\n";
}
}
- else
- {
- if (idealSampleHi == result)
- {
- return true;
- }
- }
-
- // Increment step
-
- // Represents whether the increment at a position wraps and should "carry" to the next place
- bool carry = true;
-
- for (deUint8 levelNdx = 0; levelNdx < levels; ++levelNdx)
+ }
+ else
+ {
+ if (isInRange(result, idealSampleHiMin, idealSampleHiMax))
{
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
- {
- if (carry)
- {
- carry = false;
- deInt32& n = weightSteps[levelNdx][compNdx];
-
- if (n++ == weightStepsMax[levelNdx][compNdx])
- {
- n = weightStepsMin[levelNdx][compNdx];
- carry = true;
- }
- }
- else
- {
- break;
- }
- }
-
- if (!carry)
- {
- break;
- }
+ return true;
}
-
- if (carry)
+ else
{
- done = true;
+ report << "Failed comparison\n";
}
}
- report << "Failed comparison against all possible weights\n\n";
-
return false;
}
-bool SampleVerifier::verifySampleUnnormalizedCoords (const SampleArguments& args,
- const Vec4& result,
- const Vec3& unnormalizedCoord,
- const Vec3& unnormalizedCoordLo,
- const Vec2& lodBounds,
- deUint8 level,
- VkSamplerMipmapMode mipmapFilter,
- std::ostream& report) const
+bool SampleVerifier::verifySampleTexelGridCoords (const SampleArguments& args,
+ const Vec4& result,
+ const IVec3& gridCoordHi,
+ const IVec3& gridCoordLo,
+ const Vec2& lodBounds,
+ int level,
+ VkSamplerMipmapMode mipmapFilter,
+ std::ostream& report) const
{
- const deUint8 layer = m_imParams.isArrayed ? (deUint8) deRoundEven(args.layer) : 0U;
+ const int layer = m_imParams.isArrayed ? (int)deRoundEven(args.layer) : 0U;
+ const IVec3 gridCoord[2] = {gridCoordHi, gridCoordLo};
- const bool canBeMinified = lodBounds[1] > 0.0f;
- const bool canBeMagnified = lodBounds[0] <= 0.0f;
+ IVec3 baseTexel[2];
+ IVec3 texelGridOffset[2];
+
+ for (int levelNdx = 0; levelNdx < 2; ++levelNdx)
+ {
+ calcTexelBaseOffset(gridCoord[levelNdx], m_coordBits, baseTexel[levelNdx], texelGridOffset[levelNdx]);
+ }
+
+ const bool canBeMinified = lodBounds[1] > 0.0f;
+ const bool canBeMagnified = lodBounds[0] <= 0.0f;
if (canBeMagnified)
{
if (m_samplerParams.magFilter == VK_FILTER_NEAREST)
{
- report << "Testing against nearest texel at " << floor(unnormalizedCoord).cast<deInt32>() << "\n";
+ report << "Testing against nearest texel at " << baseTexel[0] << "\n";
- const Vec4 ideal = fetchTexel(floor(unnormalizedCoord).cast<deInt32>(), layer, level, VK_FILTER_NEAREST);
+ Vec4 idealMin;
+ Vec4 idealMax;
- if (result == ideal)
+ fetchTexel(baseTexel[0], layer, level, VK_FILTER_NEAREST, idealMin, idealMax);
+
+ if (isInRange(result, idealMin, idealMax))
{
return true;
}
else
{
- report << "Failed against " << ideal << "\n";
+ report << "Failed against " << idealMin << " through " << idealMax << "\n";
}
}
else
{
- if (verifySampleFiltered(result, unnormalizedCoord, Vec3(0.0f), layer, level, Vec2(0.0f, 0.0f), VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, report))
+ if (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, Vec2(0.0f, 0.0f), VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, report))
return true;
}
}
if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
{
- const Vec2 lodFracBounds = lodBounds - Vec2(level);
+ const Vec2 lodFracBounds = lodBounds - Vec2((float)level);
- if (verifySampleFiltered(result, unnormalizedCoord, unnormalizedCoordLo, layer, level, lodFracBounds, m_samplerParams.minFilter, VK_SAMPLER_MIPMAP_MODE_LINEAR, report))
+ if (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, lodFracBounds, m_samplerParams.minFilter, VK_SAMPLER_MIPMAP_MODE_LINEAR, report))
return true;
}
else if (m_samplerParams.minFilter == VK_FILTER_LINEAR)
{
- if (verifySampleFiltered(result, unnormalizedCoord, Vec3(0.0f), layer, level, Vec2(0.0f, 0.0f), VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, report))
+ if (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, Vec2(0.0f, 0.0f), VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, report))
return true;
}
else
{
- report << "Testing against nearest texel at " << floor(unnormalizedCoord).cast<deInt32>() << "\n";
+ report << "Testing against nearest texel at " << baseTexel[0] << "\n";
+
+ Vec4 idealMin;
+ Vec4 idealMax;
- Vec4 ideal = fetchTexel(floor(unnormalizedCoord).cast<deInt32>(), layer, level, VK_FILTER_NEAREST);
+ fetchTexel(baseTexel[0], layer, level, VK_FILTER_NEAREST, idealMin, idealMax);
- if (result == ideal)
+ if (isInRange(result, idealMin, idealMax))
{
return true;
}
else
{
- report << "Failed against " << ideal << "\n";
+ report << "Failed against " << idealMin << " through " << idealMax << "\n";
}
}
}
const Vec4& result,
const Vec4& coord,
const Vec2& lodBounds,
- deUint8 level,
+ int level,
std::ostream& report) const
{
DE_ASSERT(level < m_imParams.levels);
mipmapFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST;
}
- Vector<double, 3> unnormalizedCoordHiDbl, unnormalizedCoordLoDbl;
+ Vec3 unnormalizedCoordMin[2];
+ Vec3 unnormalizedCoordMax[2];
+ IVec3 gridCoordMin[2];
+ IVec3 gridCoordMax[2];
- unnormalizedCoordHiDbl = coord.cast<double>().swizzle(0, 1, 2) * m_pba[level].getSize().cast<double>();
+ const FloatFormat coordFormat(-32, 32, 16, true);
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- unnormalizedCoordLoDbl = coord.cast<double>().swizzle(0, 1, 2) * m_pba[level + 1].getSize().cast<double>();
- }
+ calcUnnormalizedCoordRange(coord,
+ m_pba[level].getSize(),
+ coordFormat,
+ unnormalizedCoordMin[0],
+ unnormalizedCoordMax[0]);
- // Check if result(s) will be rounded
+ calcTexelGridCoordRange(unnormalizedCoordMin[0],
+ unnormalizedCoordMax[0],
+ m_coordBits,
+ gridCoordMin[0],
+ gridCoordMax[0]);
- bool hiIsRounded[3] = {false};
- bool loIsRounded[3] = {false};
+ report << "Level " << level << " computed unnormalized coordinate range: [" << unnormalizedCoordMin[0] << ", " << unnormalizedCoordMax[0] << "]\n";
+ report << "Level " << level << " computed texel grid coordinate range: [" << gridCoordMin[0] << ", " << gridCoordMax[0] << "]\n";
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
+ if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
{
- hiIsRounded[compNdx] = ((double) (float) unnormalizedCoordHiDbl[compNdx]) != unnormalizedCoordHiDbl[compNdx];
+ calcUnnormalizedCoordRange(coord,
+ m_pba[level+1].getSize(),
+ coordFormat,
+ unnormalizedCoordMin[1],
+ unnormalizedCoordMax[1]);
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- loIsRounded[compNdx] = ((double) (float) unnormalizedCoordLoDbl[compNdx]) != unnormalizedCoordLoDbl[compNdx];
- }
- }
+ calcTexelGridCoordRange(unnormalizedCoordMin[1],
+ unnormalizedCoordMax[1],
+ m_coordBits,
+ gridCoordMin[1],
+ gridCoordMax[1]);
- const deInt32 ulpEpsilon = (deInt32) (2.0e-5f / FLT_EPSILON);
- const deInt32 ulpOffsets[3] = {0, -ulpEpsilon, ulpEpsilon};
- deUint8 roundTypesHi[3] = {0, 0, 0};
- deUint8 roundTypesLo[3] = {0, 0, 0};
+ report << "Level " << level+1 << " computed unnormalized coordinate range: [" << unnormalizedCoordMin[1] << " - " << unnormalizedCoordMax[1] << "]\n";
+ report << "Level " << level+1 << " computed texel grid coordinate range: [" << gridCoordMin[1] << " - " << gridCoordMax[1] << "]\n";
+ }
+ else
+ {
+ unnormalizedCoordMin[1] = unnormalizedCoordMax[1] = Vec3(0.0f);
+ gridCoordMin[1] = gridCoordMax[1] = IVec3(0);
+ }
bool done = false;
- // Take into account different possible rounding modes by offsetting rounded result by ULPs
- // \todo [2016-07-15 collinbaker] This is not 100% correct; should simulate floating point arithmetic with possible rounding modes
+ IVec3 gridCoord[2] = {gridCoordMin[0], gridCoordMin[1]};
+
while (!done)
{
- Vec3 unnormalizedCoordHi;
- Vec3 unnormalizedCoordLo;
-
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
- {
- float comp = coord[compNdx];
- float compHi;
- float compLo;
-
- if (roundTypesHi[compNdx] != 0 && comp > FLT_MIN * (float) ulpEpsilon)
- {
- compHi = addUlp(comp, ulpOffsets[roundTypesHi[compNdx]]);
- }
- else
- {
- compHi = comp;
- }
-
- if (roundTypesLo[compNdx] != 0 && comp > FLT_MIN * (float) ulpEpsilon)
- {
- compLo = addUlp(comp, ulpOffsets[roundTypesLo[compNdx]]);
- }
- else
- {
- compLo = comp;
- }
-
- unnormalizedCoordHi[compNdx] = compHi * (float) m_pba[level].getSize()[compNdx];
-
- if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
- {
- unnormalizedCoordLo[compNdx] = compLo * (float) m_pba[level + 1].getSize()[compNdx];
- }
- }
-
- report << "Testing at " << unnormalizedCoordHi << ", " << unnormalizedCoordLo << "\n";
-
- if (verifySampleUnnormalizedCoords(args, result, unnormalizedCoordHi, unnormalizedCoordLo, lodBounds, level, mipmapFilter, report))
+ if (verifySampleTexelGridCoords(args, result, gridCoord[0], gridCoord[1], lodBounds, level, mipmapFilter, report))
return true;
- // Increment rounding types
+ // Get next grid coordinate to test at
+ // Represents whether the increment at a position wraps and should "carry" to the next place
bool carry = true;
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
+ for (int levelNdx = 0; levelNdx < 2; ++levelNdx)
{
- if (hiIsRounded[compNdx])
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
{
if (carry)
{
- if (roundTypesHi[compNdx] == 2)
- {
- roundTypesHi[compNdx] = 0;
- }
- else
- {
- roundTypesHi[compNdx]++;
- carry = false;
- }
- }
- else
- {
- break;
- }
- }
- }
+ deInt32& comp = gridCoord[levelNdx][compNdx];
+ ++comp;
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
- {
- if (loIsRounded[compNdx])
- {
- if (carry)
- {
- if (roundTypesLo[compNdx] == 2)
+ if (comp > gridCoordMax[levelNdx][compNdx])
{
- roundTypesLo[compNdx] = 0;
+ comp = gridCoordMin[levelNdx][compNdx];
}
else
{
- roundTypesLo[compNdx]++;
carry = false;
}
}
- else
- {
- break;
- }
}
}
- if (carry)
- {
- done = true;
- }
+ done = carry;
}
return false;
const Vec4& coord,
const Vec4& dPdx,
const Vec4& dPdy,
- deUint8 face,
+ int face,
std::ostream& report) const
{
// Will use this parameter once cubemapping is implemented completely
if (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
{
- const Vec3 mx = abs(dPdx.swizzle(0, 1, 2)) * m_imParams.size.asFloat();
- const Vec3 my = abs(dPdy.swizzle(0, 1, 2)) * m_imParams.size.asFloat();
-
- Vec2 scaleXBounds;
- Vec2 scaleYBounds;
-
- scaleXBounds[0] = de::max(de::abs(mx[0]), de::max(de::abs(mx[1]), de::abs(mx[2])));
- scaleYBounds[0] = de::max(de::abs(my[0]), de::max(de::abs(my[1]), de::abs(my[2])));
-
- scaleXBounds[1] = de::abs(mx[0]) + de::abs(mx[1]) + de::abs(mx[2]);
- scaleYBounds[1] = de::abs(my[0]) + de::abs(my[1]) + de::abs(my[2]);
-
- Vec2 scaleMaxBounds;
-
- for (deUint8 compNdx = 0; compNdx < 2; ++compNdx)
- {
- scaleMaxBounds[compNdx] = de::max(scaleXBounds[compNdx], scaleYBounds[compNdx]);
- }
-
float lodBias = m_samplerParams.lodBias;
if (m_sampleLookupSettings.hasLodBias)
lodBias += args.lodBias;
- for (deUint8 compNdx = 0; compNdx < 2; ++compNdx)
- {
- lodBounds[compNdx] = deFloatLog2(scaleMaxBounds[compNdx]);
- lodBounds[compNdx] += lodBias;
- lodBounds[compNdx] = de::clamp(lodBounds[compNdx], m_samplerParams.minLod, m_samplerParams.maxLod);
- }
+ lodBounds = calcLodBounds(dPdx.swizzle(0, 1, 2),
+ dPdy.swizzle(0, 1, 2),
+ m_imParams.size,
+ lodBias,
+ m_samplerParams.minLod,
+ m_samplerParams.maxLod);
}
else
{
DE_ASSERT(lodBounds[0] <= lodBounds[1]);
- const float q = (float) (m_imParams.levels - 1);
+ const UVec2 levelBounds = calcLevelBounds(lodBounds, m_imParams.levels, m_samplerParams.mipmapFilter);
- if (m_samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_NEAREST)
+ for (deUint32 level = levelBounds[0]; level <= levelBounds[1]; ++level)
{
- UVec2 levelBounds;
-
- if (lodBounds[0] <= 0.5f)
- {
- levelBounds[0] = 0;
- }
- else if (lodBounds[0] < q + 0.5f)
- {
- levelBounds[0] = deCeilFloatToInt32(lodBounds[0] + 0.5f) - 1;
- }
- else
- {
- levelBounds[0] = deRoundFloatToInt32(q);
- }
-
- if (lodBounds[1] < 0.5f)
- {
- levelBounds[1] = 0;
- }
- else if (lodBounds[1] < q + 0.5f)
- {
- levelBounds[1] = deFloorFloatToInt32(lodBounds[1] + 0.5f);
- }
- else
- {
- levelBounds[1] = deRoundFloatToInt32(q);
- }
+ report << "Testing at mipmap level " << level << "...\n";
- for (deUint8 level = (deUint8) levelBounds[0]; level <= (deUint8) levelBounds[1]; ++level)
- {
- const Vec2 levelLodBounds = computeLevelLodBounds(lodBounds, level);
-
- if (verifySampleMipmapLevel(args, result, coord, levelLodBounds, level, report))
- {
- return true;
- }
- }
- }
- else
- {
- UVec2 levelBounds;
+ const Vec2 levelLodBounds = calcLevelLodBounds(lodBounds, level);
- for (deUint8 compNdx = 0; compNdx < 2; ++compNdx)
+ if (verifySampleMipmapLevel(args, result, coord, levelLodBounds, level, report))
{
- if (lodBounds[compNdx] >= q)
- {
- levelBounds[compNdx] = deRoundFloatToInt32(q);
- }
- else
- {
- levelBounds[compNdx] = lodBounds[compNdx] < 0.0f ? 0 : deFloorFloatToInt32(lodBounds[compNdx]);
- }
+ return true;
}
- for (deUint8 level = (deUint8) levelBounds[0]; level <= (deUint8) levelBounds[1]; ++level)
- {
- const Vec2 levelLodBounds = computeLevelLodBounds(lodBounds, level);
-
- if (verifySampleMipmapLevel(args, result, coord, levelLodBounds, level, report))
- {
- return true;
- }
- }
+ report << "Done testing mipmap level " << level << ".\n\n";
}
return false;
// \todo [2016-07-06 collinbaker] Handle dRef
DE_ASSERT(m_samplerParams.isCompare == false);
- Vec4 coord = args.coord;
- deUint8 coordSize = 0;
+ Vec4 coord = args.coord;
+ int coordSize = 0;
if (m_imParams.dim == IMG_DIM_1D)
{
if (m_imParams.dim == IMG_DIM_CUBE)
{
- const Vec3 r = coord.swizzle(0, 1, 2);
- const Vec3 drdx = dPdx.swizzle(0, 1, 2);
- const Vec3 drdy = dPdy.swizzle(0, 1, 2);
-
- BVec3 isMajor(false);
- float rMax = de::abs(r[0]);
-
- for (deUint8 compNdx = 1; compNdx < 3; ++compNdx)
- {
- rMax = de::max(rMax, de::abs(r[compNdx]));
- }
+ const Vec3 r = coord.swizzle(0, 1, 2);
+ const Vec3 drdx = dPdx.swizzle(0, 1, 2);
+ const Vec3 drdy = dPdy.swizzle(0, 1, 2);
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
- {
- if (de::abs(r[compNdx]) == rMax)
- {
- isMajor[compNdx] = true;
- }
- }
-
- DE_ASSERT(isMajor[0] || isMajor[1] || isMajor[2]);
+ int faceBitmap = calcCandidateCubemapFaces(r);
// We must test every possible disambiguation order
- for (deUint8 i = 0; i < 3; ++i)
+ for (int faceNdx = 0; faceNdx < 6; ++faceNdx)
{
- if (!isMajor[i])
- {
- continue;
- }
+ const bool isPossible = faceBitmap & (1U << faceNdx);
- const deUint8 faceNdx = (deUint8) (2U * i + (r[i] < 0.0f ? 1U : 0U));
-
- const deUint8 compMap[6][3] =
- {
- {2, 1, 0},
- {2, 1, 0},
- {0, 2, 1},
- {0, 2, 1},
- {0, 1, 2},
- {0, 1, 2}
- };
-
- const deInt8 signMap[6][3] =
+ if (!isPossible)
{
- {-1, -1, +1},
- {+1, -1, -1},
- {+1, +1, +1},
- {+1, -1, -1},
- {+1, -1, +1},
- {-1, -1, -1}
- };
-
- Vec3 coordC;
- Vec3 dPcdx;
- Vec3 dPcdy;
-
- for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
- {
- const deUint8 mappedComp = compMap[faceNdx][compNdx];
- const deInt8 mappedSign = signMap[faceNdx][compNdx];
-
- coordC[compNdx] = r[mappedComp] * mappedSign;
- dPcdx[compNdx] = drdx[mappedComp] * mappedSign;
- dPcdy[compNdx] = drdy[mappedComp] * mappedSign;
+ continue;
}
- coordC[2] = de::abs(coordC[2]);
+ Vec2 coordFace;
+ Vec2 dPdxFace;
+ Vec2 dPdyFace;
- Vec4 coordFace;
- Vec4 dPdxFace;
- Vec4 dPdyFace;
+ calcCubemapFaceCoords(r, drdx, drdy, faceNdx, coordFace, dPdxFace, dPdyFace);
- for (deUint8 compNdx = 0; compNdx < 2; ++compNdx)
+ if (verifySampleCubemapFace(args,
+ result,
+ Vec4(coordFace[0], coordFace[1], 0.0f, 0.0f),
+ Vec4(dPdxFace[0], dPdxFace[1], 0.0f, 0.0f),
+ Vec4(dPdyFace[0], dPdyFace[1], 0.0f, 0.0f),
+ faceNdx,
+ report))
{
- coordFace[compNdx] = 0.5f * coordC[compNdx] / de::abs(coordC[2]) + 0.5f;
-
- dPdxFace[compNdx] = 0.5f * (de::abs(coordC[2]) * dPcdx[compNdx] - coordC[compNdx] * dPcdx[2]) / (coordC[2] * coordC[2]);
- dPdyFace[compNdx] = 0.5f * (de::abs(coordC[2]) * dPcdy[compNdx] - coordC[compNdx] * dPcdy[2]) / (coordC[2] * coordC[2]);
- }
-
- for (deUint8 compNdx = 2; compNdx < 4; ++compNdx)
- {
- coordFace[compNdx] = dPdxFace[compNdx] = dPdyFace[compNdx] = 0.0f;
- }
-
- if (verifySampleCubemapFace(args, result, coordFace, dPdxFace, dPdyFace, faceNdx, report))
return true;
+ }
}
return false;
#include "deUniquePtr.hpp"
+#include "tcuFloatFormat.hpp"
#include "tcuTexture.hpp"
#include "tcuVector.hpp"
ImgDim dim;
vk::VkFormat format;
tcu::IVec3 size;
- deUint8 levels;
+ int levels;
bool isArrayed;
- deUint32 arrayLayers;
+ int arrayLayers;
};
class SampleVerifier
std::string& report) const;
private:
- bool verifySampleMipmapLinear (tcu::Vec4 result,
- tcu::Vec4 sampleHi,
- tcu::Vec4 sampleLo,
- deInt32 lodStepMin,
- deInt32 lodStepMax,
- deUint32 layer,
- deUint8 levelHi) const;
bool verifySampleFiltered (const tcu::Vec4& result,
- const tcu::Vec3& unnormalizedCoordHi,
- const tcu::Vec3& unnormalizedCoordLo,
- deUint32 layer,
- deUint8 levelHi,
+ const tcu::IVec3& baseTexelHi,
+ const tcu::IVec3& baseTexelLo,
+ const tcu::IVec3& texelGridOffsetHi,
+ const tcu::IVec3& texelGridOffsetLo,
+ int layer,
+ int levelHi,
const tcu::Vec2& lodFracBounds,
vk::VkFilter filter,
vk::VkSamplerMipmapMode mipmapFilter,
std::ostream& report) const;
- bool verifySampleUnnormalizedCoords (const SampleArguments& args,
+ bool verifySampleTexelGridCoords (const SampleArguments& args,
const tcu::Vec4& result,
- const tcu::Vec3& unnormalizedCoord,
- const tcu::Vec3& unnormalizedCoordLo,
+ const tcu::IVec3& gridCoordHi,
+ const tcu::IVec3& gridCoordLo,
const tcu::Vec2& lodBounds,
- deUint8 level,
+ int level,
vk::VkSamplerMipmapMode mipmapFilter,
std::ostream& report) const;
const tcu::Vec4& result,
const tcu::Vec4& coord,
const tcu::Vec2& lodFracBounds,
- deUint8 level,
+ int level,
std::ostream& report) const;
bool verifySampleCubemapFace (const SampleArguments& args,
const tcu::Vec4& coord,
const tcu::Vec4& dPdx,
const tcu::Vec4& dPdy,
- deUint8 face,
+ int face,
std::ostream& report) const;
bool verifySampleImpl (const SampleArguments& args,
int compNdx,
int level) const;
- tcu::Vec4 fetchTexel (const tcu::IVec3& coordIn,
- deUint32 layer,
- deUint8 level,
- vk::VkFilter filter) const;
+ void fetchTexel (const tcu::IVec3& coordIn,
+ int layer,
+ int level,
+ vk::VkFilter filter,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax) const;
+
+ void fetchTexelWrapped (const tcu::IVec3& coord,
+ int layer,
+ int level,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax) const;
- tcu::Vec4 getFilteredSample1D (const tcu::IVec3& texelBase,
+ void getFilteredSample1D (const tcu::IVec3& texelBase,
float weight,
- deUint32 layer,
- deUint8 level) const;
+ int layer,
+ int level,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax) const;
- tcu::Vec4 getFilteredSample2D (const tcu::IVec3& texelBase,
+ void getFilteredSample2D (const tcu::IVec3& texelBase,
const tcu::Vec2& weights,
- deUint32 layer,
- deUint8 level) const;
+ int layer,
+ int level,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax) const;
- tcu::Vec4 getFilteredSample3D (const tcu::IVec3& texelBase,
+ void getFilteredSample3D (const tcu::IVec3& texelBase,
const tcu::Vec3& weights,
- deUint32 layer,
- deUint8 level) const;
+ int layer,
+ int level,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax) const;
- tcu::Vec4 getFilteredSample (const tcu::IVec3& texelBase,
+ void getFilteredSample (const tcu::IVec3& texelBase,
const tcu::Vec3& weights,
- deUint32 layer,
- deUint8 level) const;
-
- void getWeightStepBounds (const tcu::Vec3& unnormalizedCoord,
- tcu::IVec3& weightStepMin,
- tcu::IVec3& weightStepMax,
- tcu::IVec3& texelBase) const;
+ int layer,
+ int level,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax) const;
void getMipmapStepBounds (const tcu::Vec2& lodFracBounds,
deInt32& stepMin,
deInt32& stepMax) const;
+ const tcu::FloatFormat m_internalFormat;
+
const ImageViewParameters& m_imParams;
const SamplerParameters& m_samplerParams;
const SampleLookupSettings& m_sampleLookupSettings;
- int m_coordBits;
- int m_mipmapBits;
+ const int m_coordBits;
+ const int m_mipmapBits;
- int m_unnormalizedDim;
+ const int m_unnormalizedDim;
const std::vector<tcu::ConstPixelBufferAccess>& m_pba;
};
--- /dev/null
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 Google 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 GPU image sample verification
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSampleVerifierUtil.hpp"
+
+#include "deMath.h"
+#include "tcuDefs.hpp"
+#include "tcuFloat.hpp"
+#include "tcuFloatFormat.hpp"
+#include "tcuInterval.hpp"
+#include "tcuTexture.hpp"
+#include "tcuTextureUtil.hpp"
+
+namespace vkt
+{
+namespace texture_filtering
+{
+namespace util
+{
+
+using namespace tcu;
+using namespace vk;
+
+deInt32 mod (const deInt32 a, const deInt32 n)
+{
+ const deInt32 result = a % n;
+
+ return (result < 0) ? result + n : result;
+}
+
+deInt32 mirror (const deInt32 n)
+{
+ if (n >= 0)
+ {
+ return n;
+ }
+ else
+ {
+ return -(1 + n);
+ }
+}
+
+UVec2 calcLevelBounds (const Vec2& lodBounds,
+ const int levelCount,
+ VkSamplerMipmapMode mipmapFilter)
+{
+ DE_ASSERT(lodBounds[0] <= lodBounds[1]);
+ DE_ASSERT(levelCount > 0);
+
+ const float q = (float) (levelCount - 1);
+
+ UVec2 levelBounds;
+
+ if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_NEAREST)
+ {
+ if (lodBounds[0] <= 0.5f)
+ {
+ levelBounds[0] = 0;
+ }
+ else if (lodBounds[0] < q + 0.5f)
+ {
+ levelBounds[0] = deCeilFloatToInt32(lodBounds[0] + 0.5f) - 1;
+ }
+ else
+ {
+ levelBounds[0] = deRoundFloatToInt32(q);
+ }
+
+ if (lodBounds[1] < 0.5f)
+ {
+ levelBounds[1] = 0;
+ }
+ else if (lodBounds[1] < q + 0.5f)
+ {
+ levelBounds[1] = deFloorFloatToInt32(lodBounds[1] + 0.5f);
+ }
+ else
+ {
+ levelBounds[1] = deRoundFloatToInt32(q);
+ }
+ }
+ else
+ {
+ for (int ndx = 0; ndx < 2; ++ndx)
+ {
+ if (lodBounds[ndx] >= q)
+ {
+ levelBounds[ndx] = deRoundFloatToInt32(q);
+ }
+ else
+ {
+ levelBounds[ndx] = lodBounds[ndx] < 0.0f ? 0 : deFloorFloatToInt32(lodBounds[ndx]);
+ }
+ }
+ }
+
+ return levelBounds;
+}
+
+Vec2 calcLevelLodBounds (const Vec2& lodBounds, int level)
+{
+ Vec2 levelLodBounds;
+
+ if (lodBounds[0] <= 0.0f)
+ {
+ levelLodBounds[0] = lodBounds[0];
+ }
+ else
+ {
+ levelLodBounds[0] = de::max(lodBounds[0], (float) level);
+ }
+
+ levelLodBounds[1] = de::min(lodBounds[1], (float) level + 1.0f);
+
+ return levelLodBounds;
+}
+
+float addUlp (float num, deInt32 ulp)
+{
+ // Note: adding positive ulp always moves float away from zero
+
+ const tcu::Float32 f(num);
+
+ DE_ASSERT(!f.isNaN() && !f.isInf());
+ DE_ASSERT(num > FLT_MIN * (float) ulp || num < FLT_MIN * (float) ulp);
+
+ return tcu::Float32(f.bits() + ulp).asFloat();
+}
+
+void wrapTexelGridCoordLinear (IVec3& baseTexel,
+ IVec3& texelGridOffset,
+ const int coordBits,
+ const ImgDim dim)
+{
+ const int subdivisions = 1 << coordBits;
+
+ int numComp;
+
+ switch (dim)
+ {
+ case IMG_DIM_1D:
+ numComp = 1;
+ break;
+
+ case IMG_DIM_2D:
+ numComp = 2;
+ break;
+
+ case IMG_DIM_CUBE:
+ numComp = 2;
+ break;
+
+ case IMG_DIM_3D:
+ numComp = 3;
+ break;
+
+ default:
+ numComp = 0;
+ break;
+ }
+
+ for (int compNdx = 0; compNdx < numComp; ++compNdx)
+ {
+ texelGridOffset[compNdx] -= subdivisions / (int) 2;
+
+ if (texelGridOffset[compNdx] < 0)
+ {
+ baseTexel [compNdx] -= 1;
+ texelGridOffset[compNdx] += (deInt32) subdivisions;
+ }
+ }
+}
+
+void calcTexelBaseOffset (const IVec3& gridCoord,
+ const int coordBits,
+ IVec3& baseTexel,
+ IVec3& texelGridOffset)
+{
+ const int subdivisions = (int) 1 << coordBits;
+
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
+ {
+ // \todo [2016-07-22 collinbaker] Do floor division to properly handle negative coords
+ baseTexel[compNdx] = gridCoord[compNdx] / (deInt32) subdivisions;
+ texelGridOffset[compNdx] = gridCoord[compNdx] % (deInt32) subdivisions;
+ }
+}
+
+void calcTexelGridCoordRange (const Vec3& unnormalizedCoordMin,
+ const Vec3& unnormalizedCoordMax,
+ const int coordBits,
+ IVec3& gridCoordMin,
+ IVec3& gridCoordMax)
+{
+ const int subdivisions = 1 << coordBits;
+
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
+ {
+ const float comp[2] = {unnormalizedCoordMin[compNdx],
+ unnormalizedCoordMax[compNdx]};
+
+ float fracPart[2];
+ double intPart[2];
+
+ for (int ndx = 0; ndx < 2; ++ndx)
+ {
+ fracPart[ndx] = (float) deModf(comp[ndx], &intPart[ndx]);
+
+ if (comp[ndx] < 0.0f)
+ {
+ intPart [ndx] -= 1.0;
+ fracPart[ndx] += 1.0f;
+ }
+ }
+
+ const deInt32 nearestTexelGridOffsetMin = (deInt32) deFloor(intPart[0]);
+ const deInt32 nearestTexelGridOffsetMax = (deInt32) deFloor(intPart[1]);
+
+ const deInt32 subTexelGridCoordMin = de::max((deInt32) deFloor(fracPart[0] * (float) subdivisions), (deInt32) 0);
+ const deInt32 subTexelGridCoordMax = de::min((deInt32) deCeil (fracPart[1] * (float) subdivisions), (deInt32) (subdivisions - 1));
+
+ gridCoordMin[compNdx] = nearestTexelGridOffsetMin * (deInt32) subdivisions + subTexelGridCoordMin;
+ gridCoordMax[compNdx] = nearestTexelGridOffsetMax * (deInt32) subdivisions + subTexelGridCoordMax;
+ }
+}
+
+void calcUnnormalizedCoordRange (const Vec4& coord,
+ const IVec3& levelSize,
+ const FloatFormat& internalFormat,
+ Vec3& unnormalizedCoordMin,
+ Vec3& unnormalizedCoordMax)
+{
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
+ {
+ const int size = levelSize[compNdx];
+
+ Interval coordInterval = Interval(coord[compNdx]);
+ coordInterval = internalFormat.roundOut(coordInterval, false);
+
+ Interval unnormalizedCoordInterval = coordInterval * Interval((double) size);
+ unnormalizedCoordInterval = internalFormat.roundOut(unnormalizedCoordInterval, false);
+
+ unnormalizedCoordMin[compNdx] = (float)unnormalizedCoordInterval.lo();
+ unnormalizedCoordMax[compNdx] = (float)unnormalizedCoordInterval.hi();
+ }
+}
+
+Vec2 calcLodBounds (const Vec3& dPdx,
+ const Vec3& dPdy,
+ const IVec3 size,
+ const float lodBias,
+ const float lodMin,
+ const float lodMax)
+{
+ Vec2 lodBounds;
+
+ const Vec3 mx = abs(dPdx) * size.asFloat();
+ const Vec3 my = abs(dPdy) * size.asFloat();
+
+ Vec2 scaleXBounds;
+ Vec2 scaleYBounds;
+
+ scaleXBounds[0] = de::max(de::abs(mx[0]), de::max(de::abs(mx[1]), de::abs(mx[2])));
+ scaleYBounds[0] = de::max(de::abs(my[0]), de::max(de::abs(my[1]), de::abs(my[2])));
+
+ scaleXBounds[1] = de::abs(mx[0]) + de::abs(mx[1]) + de::abs(mx[2]);
+ scaleYBounds[1] = de::abs(my[0]) + de::abs(my[1]) + de::abs(my[2]);
+
+ Vec2 scaleMaxBounds;
+
+ for (int compNdx = 0; compNdx < 2; ++compNdx)
+ {
+ scaleMaxBounds[compNdx] = de::max(scaleXBounds[compNdx], scaleYBounds[compNdx]);
+ }
+
+ for (int ndx = 0; ndx < 2; ++ndx)
+ {
+ lodBounds[ndx] = deFloatLog2(scaleMaxBounds[ndx]);
+ lodBounds[ndx] += lodBias;
+ lodBounds[ndx] = de::clamp(lodBounds[ndx], lodMin, lodMax);
+ }
+
+ return lodBounds;
+}
+
+void calcCubemapFaceCoords (const Vec3& r,
+ const Vec3& drdx,
+ const Vec3& drdy,
+ const int faceNdx,
+ Vec2& coordFace,
+ Vec2& dPdxFace,
+ Vec2& dPdyFace)
+{
+ DE_ASSERT(faceNdx >= 0 && faceNdx < 6);
+
+ static const int compMap[6][3] =
+ {
+ {2, 1, 0},
+ {2, 1, 0},
+ {0, 2, 1},
+ {0, 2, 1},
+ {0, 1, 2},
+ {0, 1, 2}
+ };
+
+ static const int signMap[6][3] =
+ {
+ {-1, -1, +1},
+ {+1, -1, -1},
+ {+1, +1, +1},
+ {+1, -1, -1},
+ {+1, -1, +1},
+ {-1, -1, -1}
+ };
+
+ Vec3 coordC;
+ Vec3 dPcdx;
+ Vec3 dPcdy;
+
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
+ {
+ const int mappedComp = compMap[faceNdx][compNdx];
+ const int mappedSign = signMap[faceNdx][compNdx];
+
+ coordC[compNdx] = r [mappedComp] * (float)mappedSign;
+ dPcdx [compNdx] = drdx[mappedComp] * (float)mappedSign;
+ dPcdy [compNdx] = drdy[mappedComp] * (float)mappedSign;
+ }
+
+ DE_ASSERT(coordC[2] != 0.0f);
+ coordC[2] = de::abs(coordC[2]);
+
+ for (int compNdx = 0; compNdx < 2; ++compNdx)
+ {
+ coordFace[compNdx] = 0.5f * coordC[compNdx] / de::abs(coordC[2]) + 0.5f;
+
+ dPdxFace [compNdx] = 0.5f * (de::abs(coordC[2]) * dPcdx[compNdx] - coordC[compNdx] * dPcdx[2]) / (coordC[2] * coordC[2]);
+ dPdyFace [compNdx] = 0.5f * (de::abs(coordC[2]) * dPcdy[compNdx] - coordC[compNdx] * dPcdy[2]) / (coordC[2] * coordC[2]);
+ }
+}
+
+int calcCandidateCubemapFaces (const Vec3& r)
+{
+ deUint8 faceBitmap = 0;
+ float rMax = de::abs(r[0]);
+
+ for (int compNdx = 1; compNdx < 3; ++compNdx)
+ {
+ rMax = de::max(rMax, de::abs(r[compNdx]));
+ }
+
+ for (int compNdx = 0; compNdx < 3; ++compNdx)
+ {
+ if (de::abs(r[compNdx]) == rMax)
+ {
+ const int faceNdx = 2 * compNdx + (r[compNdx] < 0.0f ? 1 : 0);
+
+ DE_ASSERT(faceNdx < 6);
+
+ faceBitmap = faceBitmap | (deUint8) (1U << faceNdx);
+ }
+ }
+
+ DE_ASSERT(faceBitmap != 0U);
+
+ return faceBitmap;
+}
+
+deInt32 wrapTexelCoord (const deInt32 coord,
+ const int size,
+ const VkSamplerAddressMode wrap)
+{
+ deInt32 wrappedCoord = 0;
+
+ switch (wrap)
+ {
+ case VK_SAMPLER_ADDRESS_MODE_REPEAT:
+ wrappedCoord = mod(coord, size);
+ break;
+
+ case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
+ wrappedCoord = (size - 1) - mirror(mod(coord, 2 * size) - size);
+ break;
+
+ case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
+ wrappedCoord = de::clamp(coord, 0, (deInt32) size - 1);
+ break;
+
+ case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER:
+ wrappedCoord = de::clamp(coord, -1, (deInt32) size);
+ break;
+
+ case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
+ wrappedCoord = de::clamp(mirror(coord), 0, (deInt32) size - 1);
+ break;
+
+ default:
+ DE_FATAL("Invalid VkSamplerAddressMode");
+ break;
+ }
+
+ return wrappedCoord;
+}
+
+namespace
+{
+
+// Cube map adjacent faces ordered clockwise from top
+// \todo [2016-07-07 collinbaker] Verify these are correct
+static const int adjacentFaces[6][4] =
+{
+ {3, 5, 2, 4},
+ {3, 4, 2, 5},
+ {4, 0, 5, 1},
+ {5, 0, 4, 1},
+ {3, 0, 2, 1},
+ {3, 1, 2, 0}
+};
+
+static const int adjacentEdges[6][4] =
+{
+ {1, 3, 1, 1},
+ {3, 3, 3, 1},
+ {2, 2, 2, 2},
+ {0, 0, 0, 0},
+ {2, 3, 0, 1},
+ {0, 3, 2, 1}
+};
+
+static const int adjacentEdgeDirs[6][4] =
+{
+ {-1, +1, +1, +1},
+ {+1, +1, -1, +1},
+ {+1, +1, -1, -1},
+ {-1, -1, +1, +1},
+ {+1, +1, +1, +1},
+ {-1, +1, -1, +1}
+};
+
+static const int edgeComponent[4] = {0, 1, 0, 1};
+
+static const int edgeFactors[4][2] =
+{
+ {0, 0},
+ {1, 0},
+ {0, 1},
+ {0, 0}
+};
+
+} // anonymous
+
+void wrapCubemapEdge (const IVec2& coord,
+ const IVec2& size,
+ const int faceNdx,
+ IVec2& newCoord,
+ int& newFaceNdx)
+{
+ int edgeNdx = -1;
+
+ if (coord[1] < 0)
+ {
+ edgeNdx = 0;
+ }
+ else if (coord[0] > 0)
+ {
+ edgeNdx = 1;
+ }
+ else if (coord[1] > 0)
+ {
+ edgeNdx = 2;
+ }
+ else
+ {
+ edgeNdx = 3;
+ }
+
+ const int adjacentEdgeNdx = adjacentEdges[faceNdx][edgeNdx];
+ const IVec2 edgeFactor = IVec2(edgeFactors[adjacentEdgeNdx][0],
+ edgeFactors[adjacentEdgeNdx][1]);
+ const IVec2 edgeOffset = edgeFactor * (size - IVec2(1));
+
+ if (adjacentEdgeDirs[faceNdx][edgeNdx] > 0)
+ {
+ newCoord[edgeComponent[adjacentEdgeNdx]] = coord[edgeComponent[edgeNdx]];
+ }
+ else
+ {
+ newCoord[edgeComponent[adjacentEdgeNdx]] =
+ size[edgeComponent[edgeNdx]] - coord[edgeComponent[edgeNdx]] - 1;
+ }
+
+ newCoord[1 - edgeComponent[adjacentEdgeNdx]] = 0;
+ newCoord += edgeOffset;
+
+ newFaceNdx = adjacentFaces[faceNdx][edgeNdx];
+}
+
+void wrapCubemapCorner (const IVec2& coord,
+ const IVec2& size,
+ const int faceNdx,
+ int& adjacentFace1,
+ int& adjacentFace2,
+ IVec2& cornerCoord0,
+ IVec2& cornerCoord1,
+ IVec2& cornerCoord2)
+{
+ int cornerNdx = -1;
+
+ if (coord[0] < 0 && coord[1] < 0)
+ {
+ cornerNdx = 0;
+ }
+ else if (coord[0] > 0 && coord[1] < 0)
+ {
+ cornerNdx = 1;
+ }
+ else if (coord[0] > 0 && coord[1] > 0)
+ {
+ cornerNdx = 2;
+ }
+ else
+ {
+ cornerNdx = 3;
+ }
+
+ const int cornerEdges[2] = {cornerNdx, (int) ((cornerNdx + 3) % 4)};
+
+ int faceCorners[3] = {cornerNdx, 0, 0};
+
+ for (int edgeNdx = 0; edgeNdx < 2; ++edgeNdx)
+ {
+ const int faceEdge = adjacentEdges[faceNdx][cornerEdges[edgeNdx]];
+
+ bool isFlipped = (adjacentEdgeDirs[faceNdx][cornerEdges[edgeNdx]]);
+
+ if ((cornerEdges[edgeNdx] > 1) != (faceEdge > 1))
+ {
+ isFlipped = !isFlipped;
+ }
+
+ if (isFlipped)
+ {
+ faceCorners[edgeNdx + 1] = (faceEdge + 1) % 4;
+ }
+ else
+ {
+ faceCorners[edgeNdx + 1] = faceEdge;
+ }
+ }
+
+ adjacentFace1 = adjacentFaces[faceNdx][cornerEdges[0]];
+ adjacentFace2 = adjacentFaces[faceNdx][cornerEdges[1]];
+
+ IVec2* cornerCoords[3] = {&cornerCoord0, &cornerCoord1, &cornerCoord2};
+
+ for (int ndx = 0; ndx < 3; ++ndx)
+ {
+ IVec2 cornerFactor;
+
+ switch (faceCorners[faceNdx])
+ {
+ case 0:
+ cornerFactor = IVec2(0, 0);
+ break;
+
+ case 1:
+ cornerFactor = IVec2(1, 0);
+ break;
+
+ case 2:
+ cornerFactor = IVec2(1, 1);
+ break;
+
+ case 3:
+ cornerFactor = IVec2(0, 1);
+ break;
+
+ default:
+ break;
+ }
+
+ *cornerCoords[ndx] = cornerFactor * (size - IVec2(1));
+ }
+}
+
+namespace
+{
+
+deInt64 signExtend (deUint64 src, int bits)
+{
+ const deUint64 signBit = 1u << (bits-1);
+
+ src |= ~((src & signBit) - 1);
+
+ return (deInt64) src;
+}
+
+void convertFP16 (const void* fp16Ptr,
+ FloatFormat internalFormat,
+ float& resultMin,
+ float& resultMax)
+{
+ const Float16 fp16(*(const deUint16*) fp16Ptr);
+ 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)
+{
+ DE_ASSERT(numBits > 0);
+
+ const double c = (double) num;
+ deUint64 exp = numBits;
+
+ if (isSigned)
+ --exp;
+
+ const double div = (double) (((deUint64) 1 << exp) - 1);
+
+ Interval resultInterval(de::max(c / div, -1.0));
+ resultInterval = internalFormat.roundOut(resultInterval, false);
+
+ resultMin = (float) resultInterval.lo();
+ resultMax = (float) resultInterval.hi();
+}
+
+bool isPackedType (const TextureFormat::ChannelType type)
+{
+ DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+
+ switch (type)
+ {
+ case TextureFormat::UNORM_BYTE_44:
+ case TextureFormat::UNORM_SHORT_565:
+ case TextureFormat::UNORM_SHORT_555:
+ case TextureFormat::UNORM_SHORT_4444:
+ case TextureFormat::UNORM_SHORT_5551:
+ case TextureFormat::UNORM_SHORT_1555:
+ case TextureFormat::UNORM_INT_101010:
+ case TextureFormat::SNORM_INT_1010102_REV:
+ case TextureFormat::UNORM_INT_1010102_REV:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void getPackInfo (const TextureFormat texFormat,
+ IVec4& bitSizes,
+ IVec4& bitOffsets,
+ int& baseTypeBytes)
+{
+ DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+
+ switch (texFormat.type)
+ {
+ case TextureFormat::UNORM_BYTE_44:
+ bitSizes = IVec4(4, 4, 0, 0);
+ bitOffsets = IVec4(0, 4, 0, 0);
+ baseTypeBytes = 1;
+ break;
+
+ case TextureFormat::UNORM_SHORT_565:
+ bitSizes = IVec4(5, 6, 5, 0);
+ bitOffsets = IVec4(0, 5, 11, 0);
+ baseTypeBytes = 2;
+ break;
+
+ case TextureFormat::UNORM_SHORT_555:
+ bitSizes = IVec4(5, 5, 5, 0);
+ bitOffsets = IVec4(0, 5, 10, 0);
+ baseTypeBytes = 2;
+ break;
+
+ case TextureFormat::UNORM_SHORT_4444:
+ bitSizes = IVec4(4, 4, 4, 4);
+ bitOffsets = IVec4(0, 4, 8, 12);
+ baseTypeBytes = 2;
+ break;
+
+ case TextureFormat::UNORM_SHORT_5551:
+ bitSizes = IVec4(5, 5, 5, 1);
+ bitOffsets = IVec4(0, 5, 10, 15);
+ baseTypeBytes = 2;
+ break;
+
+ case TextureFormat::UNORM_SHORT_1555:
+ bitSizes = IVec4(1, 5, 5, 5);
+ bitOffsets = IVec4(0, 1, 6, 11);
+ baseTypeBytes = 2;
+ break;
+
+ case TextureFormat::UNORM_INT_101010:
+ bitSizes = IVec4(10, 10, 10, 0);
+ bitOffsets = IVec4(0, 10, 20, 0);
+ baseTypeBytes = 4;
+ break;
+
+ case TextureFormat::SNORM_INT_1010102_REV:
+ bitSizes = IVec4(2, 10, 10, 10);
+ bitOffsets = IVec4(0, 2, 12, 22);
+ baseTypeBytes = 4;
+ break;
+
+ case TextureFormat::UNORM_INT_1010102_REV:
+ bitSizes = IVec4(2, 10, 10, 10);
+ bitOffsets = IVec4(0, 2, 12, 22);
+ baseTypeBytes = 4;
+ break;
+
+ default:
+ DE_FATAL("Invalid texture channel type");
+ return;
+ }
+}
+
+template <typename BaseType>
+deUint64 unpackBits (const BaseType pack,
+ const int bitOffset,
+ const int numBits)
+{
+ DE_ASSERT(bitOffset + numBits <= 8 * (int) sizeof(BaseType));
+
+ const BaseType mask = (BaseType) (((BaseType) 1 << (BaseType) numBits) - (BaseType) 1);
+
+ return mask & (pack >> (BaseType) (8 * (int) sizeof(BaseType) - bitOffset - numBits));
+}
+
+deUint64 readChannel (const void* ptr,
+ const int byteOffset,
+ const int numBytes)
+{
+ const deUint8* cPtr = (const deUint8*) ptr + byteOffset;
+ deUint64 result = 0;
+
+ for (int byteNdx = 0; byteNdx < numBytes; ++byteNdx)
+ {
+ result = (result << 8U) | (deUint64) (cPtr[numBytes - byteNdx - 1]);
+ }
+
+ return result;
+}
+
+void convertNormalizedFormat (const void* pixelPtr,
+ TextureFormat texFormat,
+ FloatFormat internalFormat,
+ Vec4& resultMin,
+ Vec4& resultMax)
+{
+ TextureSwizzle readSwizzle = getChannelReadSwizzle(texFormat.order);
+ const TextureChannelClass chanClass = getTextureChannelClass(texFormat.type);
+
+ DE_ASSERT(getTextureChannelClass(texFormat.type) < 2);
+
+ // Information for non-packed types
+ int chanSize = -1;
+
+ // Information for packed types
+ IVec4 bitOffsets;
+ IVec4 bitSizes;
+ int baseTypeBytes = -1;
+
+ const bool isPacked = isPackedType(texFormat.type);
+
+ if (isPacked)
+ {
+ getPackInfo(texFormat, bitSizes, bitOffsets, baseTypeBytes);
+
+ // Kludge to work around deficiency in framework
+
+ if (texFormat.type == TextureFormat::UNORM_INT_1010102_REV ||
+ texFormat.type == TextureFormat::SNORM_INT_1010102_REV)
+ {
+ for (int ndx = 0; ndx < 2; ++ndx)
+ {
+ std::swap(readSwizzle.components[ndx], readSwizzle.components[3 - ndx]);
+ }
+ }
+
+ DE_ASSERT(baseTypeBytes == 1 || baseTypeBytes == 2 || baseTypeBytes == 4);
+ }
+ else
+ {
+ chanSize = getChannelSize(texFormat.type);
+ }
+
+ const bool isSigned = (chanClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT);
+ const bool isSrgb = isSRGB(texFormat);
+
+ // \todo [2016-08-01 collinbaker] Handle sRGB with correct rounding
+ DE_ASSERT(!isSrgb);
+ DE_UNREF(isSrgb);
+
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ const TextureSwizzle::Channel chan = readSwizzle.components[compNdx];
+
+ if (chan == TextureSwizzle::CHANNEL_ZERO)
+ {
+ resultMin[compNdx] = 0.0f;
+ resultMax[compNdx] = 0.0f;
+ }
+ else if (chan == TextureSwizzle::CHANNEL_ONE)
+ {
+ resultMin[compNdx] = 1.0f;
+ resultMax[compNdx] = 1.0f;
+ }
+ else
+ {
+ deUint64 chanUVal = 0;
+ int chanBits = 0;
+
+ if (isPacked)
+ {
+ deUint64 pack = readChannel(pixelPtr, 0, baseTypeBytes);
+ chanBits = bitSizes[chan];
+
+ switch (baseTypeBytes)
+ {
+ case 1:
+ chanUVal = unpackBits<deUint8>((deUint8)pack, bitOffsets[chan], bitSizes[chan]);
+ break;
+
+ case 2:
+ chanUVal = unpackBits<deUint16>((deUint16)pack, bitOffsets[chan], bitSizes[chan]);
+ break;
+
+ case 4:
+ chanUVal = unpackBits<deUint32>((deUint32)pack, bitOffsets[chan], bitSizes[chan]);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ chanUVal = readChannel(pixelPtr, chan * chanSize, chanSize);
+ chanBits = 8 * chanSize;
+ }
+
+ deInt64 chanVal = 0;
+
+ if (isSigned)
+ {
+ chanVal = signExtend(chanUVal, chanBits);
+ }
+ else
+ {
+ chanVal = (deInt64) chanUVal;
+ }
+
+ convertNormalizedInt(chanVal, chanBits, isSigned, internalFormat, resultMin[compNdx], resultMax[compNdx]);
+ }
+ }
+}
+
+void convertFloatFormat (const void* pixelPtr,
+ TextureFormat texFormat,
+ FloatFormat internalFormat,
+ Vec4& resultMin,
+ Vec4& resultMax)
+{
+ DE_ASSERT(getTextureChannelClass(texFormat.type) == TEXTURECHANNELCLASS_FLOATING_POINT);
+
+ const TextureSwizzle readSwizzle = getChannelReadSwizzle(texFormat.order);
+
+ for (int compNdx = 0; compNdx < 4; ++compNdx)
+ {
+ const TextureSwizzle::Channel chan = readSwizzle.components[compNdx];
+
+ if (chan == TextureSwizzle::CHANNEL_ZERO)
+ {
+ resultMin[compNdx] = 0.0f;
+ resultMax[compNdx] = 0.0f;
+ }
+ else if (chan == TextureSwizzle::CHANNEL_ONE)
+ {
+ resultMin[compNdx] = 1.0f;
+ resultMax[compNdx] = 1.0f;
+ }
+ else if (texFormat.type == TextureFormat::FLOAT)
+ {
+ resultMin[compNdx] = resultMax[compNdx] = *((const float*)pixelPtr + chan);
+ }
+ else if (texFormat.type == TextureFormat::HALF_FLOAT)
+ {
+ convertFP16((const deUint16*) pixelPtr + chan, internalFormat, resultMin[compNdx], resultMax[compNdx]);
+ }
+ else
+ {
+ DE_FATAL("Unsupported floating point format");
+ }
+ }
+}
+
+} // anonymous
+
+void convertFormat (const void* pixelPtr,
+ TextureFormat texFormat,
+ FloatFormat internalFormat,
+ Vec4& resultMin,
+ Vec4& resultMax)
+{
+ const TextureChannelClass chanClass = getTextureChannelClass(texFormat.type);
+
+ // \todo [2016-08-01 collinbaker] Handle float and shared exponent formats
+ if (chanClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || chanClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
+ {
+ convertNormalizedFormat(pixelPtr, texFormat, internalFormat, resultMin, resultMax);
+ }
+ else if (chanClass == TEXTURECHANNELCLASS_FLOATING_POINT)
+ {
+ convertFloatFormat(pixelPtr, texFormat, internalFormat, resultMin, resultMax);
+ }
+ else
+ {
+ DE_FATAL("Unimplemented");
+ }
+}
+
+} // util
+} // texture_filtering
+} // vkt
--- /dev/null
+#ifndef _VKTSAMPLEVERIFIERUTIL_HPP
+#define _VKTSAMPLEVERIFIERUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 Google 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 GPU image sample verification
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSampleVerifier.hpp"
+
+#include "deMath.h"
+#include "tcuFloatFormat.hpp"
+#include "tcuTexture.hpp"
+#include "vkDefs.hpp"
+
+namespace vkt
+{
+namespace texture_filtering
+{
+namespace util
+{
+
+float addUlp (float num,
+ deInt32 ulp);
+
+deInt32 mod (const deInt32 a,
+ const deInt32 n);
+deInt32 mirror (const deInt32 n);
+
+tcu::Vec2 calcLodBounds (const tcu::Vec3& dPdx,
+ const tcu::Vec3& dPdy,
+ const tcu::IVec3 size,
+ const float lodBias,
+ const float lodMin,
+ const float lodMax);
+tcu::UVec2 calcLevelBounds (const tcu::Vec2& lodBounds,
+ const int levelCount,
+ vk::VkSamplerMipmapMode mipmapFilter);
+tcu::Vec2 calcLevelLodBounds (const tcu::Vec2& lodBounds,
+ int level);
+
+void wrapTexelGridCoordLinear (tcu::IVec3& baseTexel,
+ tcu::IVec3& texelGridOffset,
+ const int coordBits,
+ const ImgDim dim);
+void calcTexelBaseOffset (const tcu::IVec3& gridCoord,
+ const int coordBits,
+ tcu::IVec3& baseTexel,
+ tcu::IVec3& texelGridOffset);
+void calcTexelGridCoordRange (const tcu::Vec3& unnormalizedCoordMin,
+ const tcu::Vec3& unnormalizedCoordMax,
+ const int coordBits,
+ tcu::IVec3& gridCoordMin,
+ tcu::IVec3& gridCoordMax);
+void calcUnnormalizedCoordRange (const tcu::Vec4& coord,
+ const tcu::IVec3& levelSize,
+ const tcu::FloatFormat& internalFormat,
+ tcu::Vec3& unnormalizedCoordMin,
+ tcu::Vec3& unnormalizedCoordMax);
+void calcCubemapFaceCoords (const tcu::Vec3& r,
+ const tcu::Vec3& drdx,
+ const tcu::Vec3& drdy,
+ const int faceNdx,
+ tcu::Vec2& coordFace,
+ tcu::Vec2& dPdxFace,
+ tcu::Vec2& dPdyFace);
+int calcCandidateCubemapFaces (const tcu::Vec3& r);
+deInt32 wrapTexelCoord (const deInt32 coord,
+ const int size,
+ const vk::VkSamplerAddressMode wrap);
+void wrapCubemapEdge (const tcu::IVec2& coord,
+ const tcu::IVec2& size,
+ const int faceNdx,
+ tcu::IVec2& newCoord,
+ int& newFaceNdx);
+void wrapCubemapCorner (const tcu::IVec2& coord,
+ const tcu::IVec2& size,
+ const int faceNdx,
+ int& adjacentFace1,
+ int& adjacentFace2,
+ tcu::IVec2& cornerCoord0,
+ tcu::IVec2& cornerCoord1,
+ tcu::IVec2& cornerCoord2);
+
+void convertFormat (const void* pixelPtr,
+ tcu::TextureFormat texFormat,
+ tcu::FloatFormat internalFormat,
+ tcu::Vec4& resultMin,
+ tcu::Vec4& resultMax);
+
+template <int Size>
+bool isEqualRelEpsilon (const tcu::Vector<float, Size>& a, const tcu::Vector<float, Size>& b, const float epsilon)
+{
+ for (int compNdx = 0; compNdx < Size; ++compNdx)
+ {
+ if (!isEqualRelEpsilon(a[compNdx], b[compNdx], epsilon))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template <int Size>
+bool isInRange (const tcu::Vector<float, Size>& v, const tcu::Vector<float, Size>& min, const tcu::Vector<float, Size>& max)
+{
+ for (int compNdx = 0; compNdx < Size; ++compNdx)
+ {
+ if (v[compNdx] < min[compNdx] || v[compNdx] > max[compNdx])
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template <int Size>
+tcu::Vector<float, Size> floor (const tcu::Vector<float, Size>& v)
+{
+ tcu::Vector<float, Size> result;
+
+ for (int compNdx = 0; compNdx < Size; ++compNdx)
+ {
+ result[compNdx] = (float)deFloor(v[compNdx]);
+ }
+
+ return result;
+}
+
+template <int Size>
+tcu::Vector<float, Size> ceil (const tcu::Vector<float, Size>& v)
+{
+ tcu::Vector<float, Size> result;
+
+ for (int compNdx = 0; compNdx < Size; ++compNdx)
+ {
+ result[compNdx] = (float)deCeil(v[compNdx]);
+ }
+
+ return result;
+}
+
+template <int Size>
+tcu::Vector<float, Size> abs (const tcu::Vector<float, Size>& v)
+{
+ tcu::Vector<float, Size> result;
+
+ for (int compNdx = 0; compNdx < Size; ++compNdx)
+ {
+ result[compNdx] = de::abs(v[compNdx]);
+ }
+
+ return result;
+}
+
+} // util
+} // texture_filtering
+} // vkt
+
+#endif // _VKTSAMPLEVERIFIERUTIL_HPP
#include "deClock.h"
#include "deMath.h"
+#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include <sstream>
case IMG_DIM_1D:
result += "1D";
break;
+
case IMG_DIM_2D:
result += "2D";
break;
+
case IMG_DIM_3D:
result += "3D";
break;
+
case IMG_DIM_CUBE:
result += "Cube";
break;
+
default:
break;
}
const SamplerParameters& samplerParams,
const SampleLookupSettings& lookupSettings)
{
- int dim;
+ int dim = -1;
switch (imParams.dim)
{
case IMG_DIM_1D:
dim = 1;
break;
+
case IMG_DIM_2D:
dim = 2;
break;
+
case IMG_DIM_3D:
dim = 3;
break;
+
case IMG_DIM_CUBE:
dim = 3;
break;
+
default:
dim = 0;
break;
if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
{
- code += ", dPdx, dPdy";
+ code += ", vec";
+ code += (char) (numCoordComp + '0');
+ code += "(dPdx), ";
+ code += "vec";
+ code += (char) (numCoordComp + '0');
+ code += "(dPdy)";
}
else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
{
const VkImageSubresourceLayers curSubresource =
{
VK_IMAGE_ASPECT_COLOR_BIT,
- (deUint32) level,
+ (deUint32)level,
0,
- (deUint32) imParams.arrayLayers
+ (deUint32)imParams.arrayLayers
};
const VkBufferImageCopy curRegion =
0,
curSubresource,
{0U, 0U, 0U},
- {(deUint32) curLevelSize[0], (deUint32) curLevelSize[1], (deUint32) curLevelSize[2]}
+ {(deUint32)curLevelSize[0], (deUint32)curLevelSize[1], (deUint32)curLevelSize[2]}
};
copyRegions.push_back(curRegion);
{
VK_IMAGE_ASPECT_COLOR_BIT,
0,
- imParams.levels,
+ (deUint32)imParams.levels,
0,
- imParams.arrayLayers
+ (deUint32)imParams.arrayLayers
};
VkImageMemoryBarrier imMemBar =
buf.get(),
im,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- (deUint32) copyRegions.size(),
+ (deUint32)copyRegions.size(),
©Regions[0]);
imMemBar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
ImageViewParameters imParams;
SamplerParameters samplerParams;
SampleLookupSettings sampleLookupSettings;
- const SampleArguments* sampleArguments;
- deUint32 numSamples;
glu::ShaderType shaderType;
};
case IMG_DIM_1D:
imType = VK_IMAGE_TYPE_1D;
break;
+
case IMG_DIM_2D:
case IMG_DIM_CUBE:
imType = VK_IMAGE_TYPE_2D;
break;
+
case IMG_DIM_3D:
imType = VK_IMAGE_TYPE_3D;
break;
+
default:
imType = VK_IMAGE_TYPE_LAST;
break;
case IMG_DIM_1D:
imViewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
break;
+
case IMG_DIM_2D:
imViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
break;
+
case IMG_DIM_CUBE:
imViewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
break;
+
default:
imViewType = VK_IMAGE_VIEW_TYPE_LAST;
break;
case IMG_DIM_1D:
imViewType = VK_IMAGE_VIEW_TYPE_1D;
break;
+
case IMG_DIM_2D:
imViewType = VK_IMAGE_VIEW_TYPE_2D;
break;
+
case IMG_DIM_3D:
imViewType = VK_IMAGE_VIEW_TYPE_3D;
break;
+
case IMG_DIM_CUBE:
imViewType = VK_IMAGE_VIEW_TYPE_CUBE;
break;
+
default:
imViewType = VK_IMAGE_VIEW_TYPE_LAST;
break;
m_pba = m_gen->getPba();
m_sampleArguments = m_gen->getSampleArgs();
- m_numSamples = (deUint32) m_sampleArguments.size();
+ m_numSamples = (deUint32)m_sampleArguments.size();
createResources();
initializeImage(m_ctx, m_im.get(), &m_pba[0], m_imParams);
m_mipmapBits,
m_pba);
+ const int maxPrintedFailures = 5;
+ int failCount = 0;
+
for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
{
if (!verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]))
{
- // Re-run with report logging
- std::string report;
- verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
-
- m_ctx.getTestContext().getLog()
- << TestLog::Message
- << "Failed verification at sample " << sampleNdx << ".\n"
- << "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
- << "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
- << "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n"
- << TestLog::EndMessage;
-
- for (int levelNdx = 0; levelNdx < m_imParams.levels; ++levelNdx)
+ if (failCount++ < maxPrintedFailures)
{
- LogImage("", "", m_pba[levelNdx]).write(m_ctx.getTestContext().getLog());
+ // Re-run with report logging
+ std::string report;
+ verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
+
+ m_ctx.getTestContext().getLog()
+ << TestLog::Section("Failed sample", "Failed sample")
+ << TestLog::Message
+ << "Sample " << sampleNdx << ".\n"
+ << "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
+ << "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
+ << "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n"
+ << "Failure report:\n" << report << "\n"
+ << TestLog::EndMessage
+ << TestLog::EndSection;
}
-
- m_ctx.getTestContext().getLog()
- << TestLog::Message
- << "Failure report:\n" << report << "\n"
- << TestLog::EndMessage;
-
- return false;
}
}
- return true;
+ m_ctx.getTestContext().getLog()
+ << TestLog::Message
+ << "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
+ << TestLog::EndMessage;
+
+ return failCount == 0;
}
void TextureFilteringTestInstance::execute (void)
mapImageType(m_imParams.dim), // imageType
m_imParams.format, // format
m_imExtent, // extent
- m_imParams.levels, // mipLevels
- m_imParams.arrayLayers, // arrayLayers
+ (deUint32)m_imParams.levels, // mipLevels
+ (deUint32)m_imParams.arrayLayers, // arrayLayers
VK_SAMPLE_COUNT_1_BIT, // samples
VK_IMAGE_TILING_OPTIMAL, // tiling
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // usage
// \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images)
VkImageSubresourceRange imViewSubresourceRange =
{
- VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
- 0, // baseMipLevel
- m_imParams.levels, // levelCount
- 0, // baseArrayLayer
- m_imParams.arrayLayers // layerCount
+ VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
+ 0, // baseMipLevel
+ (deUint32)m_imParams.levels, // levelCount
+ 0, // baseArrayLayer
+ (deUint32)m_imParams.arrayLayers // layerCount
};
if (m_imParams.dim == IMG_DIM_CUBE)
VkFilter magFilter,
VkFilter minFilter,
VkSamplerMipmapMode mipmapFilter,
- VkSamplerAddressMode wrappingMode)
+ VkSamplerAddressMode wrappingMode,
+ bool useDerivatives)
: TextureFilteringTestCase (testCtx, name, desc)
, m_format (format)
, m_minFilter (minFilter)
, m_mipmapFilter (mipmapFilter)
, m_wrappingMode (wrappingMode)
+ , m_useDerivatives (useDerivatives)
{
m_testCaseData = genTestCaseData();
init();
SampleLookupSettings sampleLookupSettings =
{
- LOOKUP_LOD_MODE_LOD, // lookupLodMode
+ m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
false, // hasLodBias
false, // isProjective
};
imParameters,
samplerParameters,
sampleLookupSettings,
- &m_args[0],
- (deUint32) m_args.size(),
glu::SHADERTYPE_FRAGMENT
};
VkFilter m_minFilter;
VkSamplerMipmapMode m_mipmapFilter;
VkSamplerAddressMode m_wrappingMode;
-
- std::vector<SampleArguments> m_args;
+ bool m_useDerivatives;
};
class Texture2DGradientTestCase::Generator : public DataGenerator
{
std::vector<SampleArguments> args;
- const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
-
- for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
+ if (m_testCase->m_useDerivatives)
+ {
+ struct
+ {
+ Vec4 dPdx;
+ Vec4 dPdy;
+ }
+ derivativePairs[] =
+ {
+ {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
+ {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
+ {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
+ {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
+ {Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)}
+ };
+
+ for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
+ {
+ for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
+ {
+ for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
+ {
+ SampleArguments cur;
+ cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
+ (float)j / (float)(2 * m_testCase->m_dimensions[1]),
+ 0.0f, 0.0f);
+ cur.dPdx = derivativePairs[derivNdx].dPdx;
+ cur.dPdy = derivativePairs[derivNdx].dPdy;
+
+ args.push_back(cur);
+ }
+ }
+ }
+ }
+ else
{
- for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
+ const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
+
+ for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
{
- for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
+ for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
{
- SampleArguments cur;
- cur.coord = Vec4((float) i / (float) (2 * m_testCase->m_dimensions[0]),
- (float) j / (float) (2 * m_testCase->m_dimensions[1]),
- 0.0f, 0.0f);
- cur.lod = lodList[lodNdx];
+ for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
+ {
+ SampleArguments cur;
+ cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
+ (float)j / (float)(2 * m_testCase->m_dimensions[1]),
+ 0.0f, 0.0f);
+ cur.lod = lodList[lodNdx];
- args.push_back(cur);
+ args.push_back(cur);
+ }
}
}
}
VK_FORMAT_R8G8_SNORM,
VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_R8G8B8A8_SNORM,
- VK_FORMAT_R8G8B8A8_SRGB,
+// VK_FORMAT_R8G8B8A8_SRGB,
VK_FORMAT_B8G8R8A8_UNORM,
- VK_FORMAT_B8G8R8A8_SRGB,
+// VK_FORMAT_B8G8R8A8_SRGB,
VK_FORMAT_A8B8G8R8_UNORM_PACK32,
VK_FORMAT_A8B8G8R8_SNORM_PACK32,
- VK_FORMAT_A8B8G8R8_SRGB_PACK32,
+// VK_FORMAT_A8B8G8R8_SRGB_PACK32,
VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_FORMAT_R16_SFLOAT,
VK_FORMAT_R16G16_SFLOAT,
VK_FORMAT_R16G16B16A16_SFLOAT,
- VK_FORMAT_B10G11R11_UFLOAT_PACK32,
- VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
+ VK_FORMAT_R32_SFLOAT,
+ VK_FORMAT_R32G32_SFLOAT,
+ VK_FORMAT_R32G32B32A32_SFLOAT,
+// VK_FORMAT_B10G11R11_UFLOAT_PACK32,
+// VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
};
const IVec3 size(32, 32, 1);
for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
{
- std::string prefix = getFormatName(formats[formatNdx]);
+ std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
Texture2DGradientTestCase* testCaseNearest =
new Texture2DGradientTestCase(
VK_FILTER_NEAREST,
VK_FILTER_NEAREST,
VK_SAMPLER_MIPMAP_MODE_NEAREST,
- VK_SAMPLER_ADDRESS_MODE_REPEAT);
+ VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ false);
tests->addChild(testCaseNearest);
VK_FILTER_LINEAR,
VK_FILTER_LINEAR,
VK_SAMPLER_MIPMAP_MODE_LINEAR,
- VK_SAMPLER_ADDRESS_MODE_REPEAT);
+ VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ false);
tests->addChild(testCaseLinear);
}
return tests.release();
}
+TestCaseGroup* create2DDerivTests (TestContext& testCtx)
+{
+ de::MovePtr<TestCaseGroup> tests(
+ new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
+
+ const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
+ const VkSamplerAddressMode wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ const IVec3 size = IVec3(16, 16, 1);
+
+ const VkFilter filters[2] =
+ {
+ VK_FILTER_NEAREST,
+ VK_FILTER_LINEAR
+ };
+
+ const VkSamplerMipmapMode mipmapFilters[2] =
+ {
+ VK_SAMPLER_MIPMAP_MODE_NEAREST,
+ VK_SAMPLER_MIPMAP_MODE_LINEAR,
+ };
+
+ for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
+ {
+ for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
+ {
+ for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
+ {
+ std::ostringstream caseName;
+
+ switch (filters[magFilterNdx])
+ {
+ case VK_FILTER_NEAREST:
+ caseName << "nearest";
+ break;
+
+ case VK_FILTER_LINEAR:
+ caseName << "linear";
+ break;
+
+ default:
+ break;
+ }
+
+ switch (filters[minFilterNdx])
+ {
+ case VK_FILTER_NEAREST:
+ caseName << "_nearest";
+ break;
+
+ case VK_FILTER_LINEAR:
+ caseName << "_linear";
+ break;
+
+ default:
+ break;
+ }
+
+ caseName << "_mipmap";
+
+ switch (mipmapFilters[mipmapFilterNdx])
+ {
+ case VK_SAMPLER_MIPMAP_MODE_NEAREST:
+ caseName << "_nearest";
+ break;
+
+ case VK_SAMPLER_MIPMAP_MODE_LINEAR:
+ caseName << "_linear";
+ break;
+
+ default:
+ break;
+ }
+
+ Texture2DGradientTestCase* testCase =
+ new Texture2DGradientTestCase(
+ testCtx,
+ caseName.str().c_str(),
+ "...",
+ mapVkFormat(format),
+ size,
+ filters[magFilterNdx],
+ filters[minFilterNdx],
+ mipmapFilters[mipmapFilterNdx],
+ wrappingMode,
+ true);
+
+ tests->addChild(testCase);
+ }
+ }
+ }
+
+ return tests.release();
+}
+
TestCaseGroup* create2DSizeTests (TestContext& testCtx)
{
de::MovePtr<TestCaseGroup> tests(
case VK_FILTER_NEAREST:
caseName << "_nearest";
break;
+
case VK_FILTER_LINEAR:
caseName << "_linear";
break;
+
default:
break;
}
case VK_FILTER_NEAREST:
caseName << "_nearest";
break;
+
case VK_FILTER_LINEAR:
caseName << "_linear";
break;
+
default:
break;
}
case VK_SAMPLER_MIPMAP_MODE_NEAREST:
caseName << "_mipmap_nearest";
break;
+
case VK_SAMPLER_MIPMAP_MODE_LINEAR:
caseName << "_mipmap_linear";
break;
+
default:
break;
}
case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
caseName << "_clamp";
break;
+
case VK_SAMPLER_ADDRESS_MODE_REPEAT:
caseName << "_repeat";
break;
+
default:
break;
}
filters[magFilterNdx],
filters[minFilterNdx],
mipmapFilters[mipmapFilterNdx],
- wrappingModes[wrappingModeNdx]);
+ wrappingModes[wrappingModeNdx],
+ false);
tests->addChild(testCase);
}
tests->addChild(create2DSizeTests(testCtx));
tests->addChild(create2DFormatTests(testCtx));
+ tests->addChild(create2DDerivTests(testCtx));
return tests.release();
}
, m_lo (m_hasNaN ? TCU_INFINITY : val)
, m_hi (m_hasNaN ? -TCU_INFINITY : val) {}
+ Interval (bool hasNaN_, double lo_, double hi_)
+ : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_) {}
+
Interval (const Interval& a, const Interval& b)
: m_hasNaN (a.m_hasNaN || b.m_hasNaN)
, m_lo (de::min(a.lo(), b.lo()))
}
private:
- Interval (bool hasNaN_, double lo_, double hi_)
- : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_) {}
bool m_hasNaN;
double m_lo;
double m_hi;
return de::min(rounded, maxUint24);
}
-int getChannelSize (TextureFormat::ChannelType type)
-{
- // make sure this table is updated if format table is updated
- DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
-
- switch (type)
- {
- case TextureFormat::SNORM_INT8: return 1;
- case TextureFormat::SNORM_INT16: return 2;
- case TextureFormat::SNORM_INT32: return 4;
- case TextureFormat::UNORM_INT8: return 1;
- case TextureFormat::UNORM_INT16: return 2;
- case TextureFormat::UNORM_INT24: return 3;
- case TextureFormat::UNORM_INT32: return 4;
- case TextureFormat::SIGNED_INT8: return 1;
- case TextureFormat::SIGNED_INT16: return 2;
- case TextureFormat::SIGNED_INT32: return 4;
- case TextureFormat::UNSIGNED_INT8: return 1;
- case TextureFormat::UNSIGNED_INT16: return 2;
- case TextureFormat::UNSIGNED_INT24: return 3;
- case TextureFormat::UNSIGNED_INT32: return 4;
- case TextureFormat::HALF_FLOAT: return 2;
- case TextureFormat::FLOAT: return 4;
- case TextureFormat::FLOAT64: return 8;
- default:
- DE_ASSERT(DE_FALSE);
- return 0;
- }
-}
-
inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
}
}
+int getChannelSize (TextureFormat::ChannelType type)
+{
+ // make sure this table is updated if format table is updated
+ DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+
+ switch (type)
+ {
+ case TextureFormat::SNORM_INT8: return 1;
+ case TextureFormat::SNORM_INT16: return 2;
+ case TextureFormat::SNORM_INT32: return 4;
+ case TextureFormat::UNORM_INT8: return 1;
+ case TextureFormat::UNORM_INT16: return 2;
+ case TextureFormat::UNORM_INT24: return 3;
+ case TextureFormat::UNORM_INT32: return 4;
+ case TextureFormat::SIGNED_INT8: return 1;
+ case TextureFormat::SIGNED_INT16: return 2;
+ case TextureFormat::SIGNED_INT32: return 4;
+ case TextureFormat::UNSIGNED_INT8: return 1;
+ case TextureFormat::UNSIGNED_INT16: return 2;
+ case TextureFormat::UNSIGNED_INT24: return 3;
+ case TextureFormat::UNSIGNED_INT32: return 4;
+ case TextureFormat::HALF_FLOAT: return 2;
+ case TextureFormat::FLOAT: return 4;
+ case TextureFormat::FLOAT64: return 8;
+ default:
+ DE_ASSERT(DE_FALSE);
+ return 0;
+ }
+}
+
/** Get pixel size in bytes. */
int getPixelSize (TextureFormat format)
{
bool isValid (TextureFormat format);
int getPixelSize (TextureFormat format);
int getNumUsedChannels (TextureFormat::ChannelOrder order);
+int getChannelSize (TextureFormat::ChannelType type);
/*--------------------------------------------------------------------*//*!
* \brief Texture swizzle