From: Collin Baker Date: Mon, 25 Jul 2016 21:35:03 +0000 (-0700) Subject: Improvements to sample verification code X-Git-Tag: upstream/0.1.0~752^2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=afa7d2831523587d80e5540ffb7f75adf418ce5f;p=platform%2Fupstream%2FVK-GL-CTS.git Improvements to sample verification code Refactoring and improvements to code in vktSampleVerifier.cpp; Moved much functionality into separate functions and cleaned up some quick fixes I had made previously. Change-Id: I7a02ee0cbe009946ec1126e1e77141596cf1c028 --- diff --git a/Android.mk b/Android.mk index 7a51356..e5c7836 100644 --- a/Android.mk +++ b/Android.mk @@ -853,6 +853,7 @@ LOCAL_SRC_FILES := \ 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 \ diff --git a/android/cts/master/com.drawelements.deqp.vk.xml b/android/cts/master/com.drawelements.deqp.vk.xml index d6b493f..0edc7c0 100644 --- a/android/cts/master/com.drawelements.deqp.vk.xml +++ b/android/cts/master/com.drawelements.deqp.vk.xml @@ -367984,130 +367984,144 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + - + - + - + diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt index ba66e88..e5d26d0 100644 --- a/android/cts/master/vk-master.txt +++ b/android/cts/master/vk-master.txt @@ -114527,45 +114527,49 @@ dEQP-VK.texture_filtering.explicit_lod.2d.sizes.128x128_linear_linear_mipmap_nea 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 diff --git a/external/vulkancts/modules/vulkan/texture_filtering/CMakeLists.txt b/external/vulkancts/modules/vulkan/texture_filtering/CMakeLists.txt index 41a40be..01861e9 100644 --- a/external/vulkancts/modules/vulkan/texture_filtering/CMakeLists.txt +++ b/external/vulkancts/modules/vulkan/texture_filtering/CMakeLists.txt @@ -5,6 +5,8 @@ set(DEQP_VK_TEXTURE_FILTERING_SRCS vktTextureFilteringTests.hpp vktSampleVerifier.cpp vktSampleVerifier.hpp + vktSampleVerifierUtil.cpp + vktSampleVerifierUtil.hpp vktTextureFilteringExplicitLodTests.cpp vktTextureFilteringExplicitLodTests.hpp ) diff --git a/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.cpp b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.cpp index dd01b1a..5e6e7c1 100644 --- a/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.cpp +++ b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.cpp @@ -22,6 +22,7 @@ *//*--------------------------------------------------------------------*/ #include "vktSampleVerifier.hpp" +#include "vktSampleVerifierUtil.hpp" #include "deMath.h" #include "tcuFloat.hpp" @@ -38,180 +39,27 @@ namespace texture_filtering 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 -bool isEqualRelEpsilon (const Vector& a, const Vector& 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 -Vector floor (const Vector& v) -{ - Vector result; - - for (int compNdx = 0; compNdx < Size; ++compNdx) - { - result[compNdx] = (float)deFloor(v[compNdx]); - } - - return result; -} - -template -Vector ceil (const Vector& v) -{ - Vector result; - - for (int compNdx = 0; compNdx < Size; ++compNdx) - { - result[compNdx] = (float)deCeil(v[compNdx]); - } - - return result; -} - -template -Vector abs (const Vector& v) -{ - Vector 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, @@ -220,36 +68,56 @@ SampleVerifier::SampleVerifier (const ImageViewParameters& imParams, int coordBits, int mipmapBits, const std::vector& 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; @@ -264,206 +132,100 @@ Vec4 SampleVerifier::fetchTexel (const IVec3& coordIn, deUint32 layer, deUint8 l // 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]); } @@ -473,168 +235,214 @@ Vec4 SampleVerifier::fetchTexel (const IVec3& coordIn, deUint32 layer, deUint8 l 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); } } @@ -643,20 +451,22 @@ void SampleVerifier::getMipmapStepBounds (const Vec2& lodFracBounds, 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, @@ -665,120 +475,96 @@ bool SampleVerifier::verifySampleFiltered (const Vec4& result, 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(), 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(), 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; } @@ -787,70 +573,44 @@ bool SampleVerifier::verifySampleFiltered (const Vec4& result, 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) { @@ -858,22 +618,25 @@ bool SampleVerifier::verifySampleUnnormalizedCoords (const SampleArguments& args if (m_samplerParams.magFilter == VK_FILTER_NEAREST) { - report << "Testing against nearest texel at " << floor(unnormalizedCoord).cast() << "\n"; + report << "Testing against nearest texel at " << baseTexel[0] << "\n"; - const Vec4 ideal = fetchTexel(floor(unnormalizedCoord).cast(), 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; } } @@ -884,29 +647,32 @@ bool SampleVerifier::verifySampleUnnormalizedCoords (const SampleArguments& args 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() << "\n"; + report << "Testing against nearest texel at " << baseTexel[0] << "\n"; + + Vec4 idealMin; + Vec4 idealMax; - Vec4 ideal = fetchTexel(floor(unnormalizedCoord).cast(), 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"; } } } @@ -918,7 +684,7 @@ bool SampleVerifier::verifySampleMipmapLevel (const SampleArguments& args, const Vec4& result, const Vec4& coord, const Vec2& lodBounds, - deUint8 level, + int level, std::ostream& report) const { DE_ASSERT(level < m_imParams.levels); @@ -930,136 +696,88 @@ bool SampleVerifier::verifySampleMipmapLevel (const SampleArguments& args, mipmapFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST; } - Vector unnormalizedCoordHiDbl, unnormalizedCoordLoDbl; + Vec3 unnormalizedCoordMin[2]; + Vec3 unnormalizedCoordMax[2]; + IVec3 gridCoordMin[2]; + IVec3 gridCoordMax[2]; - unnormalizedCoordHiDbl = coord.cast().swizzle(0, 1, 2) * m_pba[level].getSize().cast(); + const FloatFormat coordFormat(-32, 32, 16, true); - if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR) - { - unnormalizedCoordLoDbl = coord.cast().swizzle(0, 1, 2) * m_pba[level + 1].getSize().cast(); - } + 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; @@ -1070,7 +788,7 @@ bool SampleVerifier::verifySampleCubemapFace (const SampleArguments& args, 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 @@ -1080,36 +798,17 @@ bool SampleVerifier::verifySampleCubemapFace (const SampleArguments& args, 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 { @@ -1118,73 +817,20 @@ bool SampleVerifier::verifySampleCubemapFace (const SampleArguments& args, 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; @@ -1198,8 +844,8 @@ bool SampleVerifier::verifySampleImpl (const SampleArguments& args, // \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) { @@ -1231,94 +877,39 @@ bool SampleVerifier::verifySampleImpl (const SampleArguments& args, 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; diff --git a/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.hpp b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.hpp index 28981d6..7316bac 100644 --- a/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.hpp +++ b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifier.hpp @@ -27,6 +27,7 @@ #include "deUniquePtr.hpp" +#include "tcuFloatFormat.hpp" #include "tcuTexture.hpp" #include "tcuVector.hpp" @@ -112,10 +113,10 @@ struct ImageViewParameters ImgDim dim; vk::VkFormat format; tcu::IVec3 size; - deUint8 levels; + int levels; bool isArrayed; - deUint32 arrayLayers; + int arrayLayers; }; class SampleVerifier @@ -136,30 +137,25 @@ public: 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; @@ -167,7 +163,7 @@ private: 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, @@ -175,7 +171,7 @@ private: 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, @@ -186,48 +182,61 @@ private: 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& m_pba; }; diff --git a/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.cpp b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.cpp new file mode 100644 index 0000000..9496f2d --- /dev/null +++ b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.cpp @@ -0,0 +1,952 @@ +/*------------------------------------------------------------------------- + * 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 +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)pack, bitOffsets[chan], bitSizes[chan]); + break; + + case 2: + chanUVal = unpackBits((deUint16)pack, bitOffsets[chan], bitSizes[chan]); + break; + + case 4: + chanUVal = unpackBits((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 diff --git a/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.hpp b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.hpp new file mode 100644 index 0000000..e1566c6 --- /dev/null +++ b/external/vulkancts/modules/vulkan/texture_filtering/vktSampleVerifierUtil.hpp @@ -0,0 +1,179 @@ +#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 +bool isEqualRelEpsilon (const tcu::Vector& a, const tcu::Vector& b, const float epsilon) +{ + for (int compNdx = 0; compNdx < Size; ++compNdx) + { + if (!isEqualRelEpsilon(a[compNdx], b[compNdx], epsilon)) + { + return false; + } + } + + return true; +} + +template +bool isInRange (const tcu::Vector& v, const tcu::Vector& min, const tcu::Vector& max) +{ + for (int compNdx = 0; compNdx < Size; ++compNdx) + { + if (v[compNdx] < min[compNdx] || v[compNdx] > max[compNdx]) + { + return false; + } + } + + return true; +} + +template +tcu::Vector floor (const tcu::Vector& v) +{ + tcu::Vector result; + + for (int compNdx = 0; compNdx < Size; ++compNdx) + { + result[compNdx] = (float)deFloor(v[compNdx]); + } + + return result; +} + +template +tcu::Vector ceil (const tcu::Vector& v) +{ + tcu::Vector result; + + for (int compNdx = 0; compNdx < Size; ++compNdx) + { + result[compNdx] = (float)deCeil(v[compNdx]); + } + + return result; +} + +template +tcu::Vector abs (const tcu::Vector& v) +{ + tcu::Vector result; + + for (int compNdx = 0; compNdx < Size; ++compNdx) + { + result[compNdx] = de::abs(v[compNdx]); + } + + return result; +} + +} // util +} // texture_filtering +} // vkt + +#endif // _VKTSAMPLEVERIFIERUTIL_HPP diff --git a/external/vulkancts/modules/vulkan/texture_filtering/vktTextureFilteringExplicitLodTests.cpp b/external/vulkancts/modules/vulkan/texture_filtering/vktTextureFilteringExplicitLodTests.cpp index ec93f90..3711c99 100644 --- a/external/vulkancts/modules/vulkan/texture_filtering/vktTextureFilteringExplicitLodTests.cpp +++ b/external/vulkancts/modules/vulkan/texture_filtering/vktTextureFilteringExplicitLodTests.cpp @@ -44,6 +44,7 @@ #include "deClock.h" #include "deMath.h" +#include "deStringUtil.hpp" #include "deUniquePtr.hpp" #include @@ -74,15 +75,19 @@ string genSamplerDeclaration(const ImageViewParameters& imParams, 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; } @@ -104,22 +109,26 @@ string genLookupCode(const ImageViewParameters& imParams, 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; @@ -212,7 +221,12 @@ string genLookupCode(const ImageViewParameters& imParams, 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) { @@ -300,9 +314,9 @@ void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba const VkImageSubresourceLayers curSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, - (deUint32) level, + (deUint32)level, 0, - (deUint32) imParams.arrayLayers + (deUint32)imParams.arrayLayers }; const VkBufferImageCopy curRegion = @@ -312,7 +326,7 @@ void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba 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); @@ -334,9 +348,9 @@ void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba { VK_IMAGE_ASPECT_COLOR_BIT, 0, - imParams.levels, + (deUint32)imParams.levels, 0, - imParams.arrayLayers + (deUint32)imParams.arrayLayers }; VkImageMemoryBarrier imMemBar = @@ -381,7 +395,7 @@ void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba buf.get(), im, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - (deUint32) copyRegions.size(), + (deUint32)copyRegions.size(), ©Regions[0]); imMemBar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -425,8 +439,6 @@ struct TestCaseData ImageViewParameters imParams; SamplerParameters samplerParams; SampleLookupSettings sampleLookupSettings; - const SampleArguments* sampleArguments; - deUint32 numSamples; glu::ShaderType shaderType; }; @@ -473,13 +485,16 @@ VkImageType mapImageType (ImgDim dim) 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; @@ -499,12 +514,15 @@ VkImageViewType mapImageViewType (const ImageViewParameters& imParams) 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; @@ -517,15 +535,19 @@ VkImageViewType mapImageViewType (const ImageViewParameters& imParams) 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; @@ -640,7 +662,7 @@ TestStatus TextureFilteringTestInstance::runTest (void) 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); @@ -694,37 +716,39 @@ bool TextureFilteringTestInstance::verify (void) 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) @@ -803,8 +827,8 @@ void TextureFilteringTestInstance::createResources (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 @@ -829,11 +853,11 @@ void TextureFilteringTestInstance::createResources (void) // \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) @@ -972,7 +996,8 @@ public: VkFilter magFilter, VkFilter minFilter, VkSamplerMipmapMode mipmapFilter, - VkSamplerAddressMode wrappingMode) + VkSamplerAddressMode wrappingMode, + bool useDerivatives) : TextureFilteringTestCase (testCtx, name, desc) , m_format (format) @@ -981,6 +1006,7 @@ public: , m_minFilter (minFilter) , m_mipmapFilter (mipmapFilter) , m_wrappingMode (wrappingMode) + , m_useDerivatives (useDerivatives) { m_testCaseData = genTestCaseData(); init(); @@ -997,7 +1023,7 @@ protected: SampleLookupSettings sampleLookupSettings = { - LOOKUP_LOD_MODE_LOD, // lookupLodMode + m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode false, // hasLodBias false, // isProjective }; @@ -1037,8 +1063,6 @@ protected: imParameters, samplerParameters, sampleLookupSettings, - &m_args[0], - (deUint32) m_args.size(), glu::SHADERTYPE_FRAGMENT }; @@ -1052,8 +1076,7 @@ private: VkFilter m_minFilter; VkSamplerMipmapMode m_mipmapFilter; VkSamplerAddressMode m_wrappingMode; - - std::vector m_args; + bool m_useDerivatives; }; class Texture2DGradientTestCase::Generator : public DataGenerator @@ -1110,21 +1133,58 @@ public: { std::vector 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); + } } } } @@ -1158,25 +1218,28 @@ TestCaseGroup* create2DFormatTests (TestContext& testCtx) 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( @@ -1188,7 +1251,8 @@ TestCaseGroup* create2DFormatTests (TestContext& testCtx) 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); @@ -1202,7 +1266,8 @@ TestCaseGroup* create2DFormatTests (TestContext& testCtx) 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); } @@ -1210,6 +1275,100 @@ TestCaseGroup* create2DFormatTests (TestContext& testCtx) return tests.release(); } +TestCaseGroup* create2DDerivTests (TestContext& testCtx) +{ + de::MovePtr 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 tests( @@ -1266,9 +1425,11 @@ TestCaseGroup* create2DSizeTests (TestContext& testCtx) case VK_FILTER_NEAREST: caseName << "_nearest"; break; + case VK_FILTER_LINEAR: caseName << "_linear"; break; + default: break; } @@ -1278,9 +1439,11 @@ TestCaseGroup* create2DSizeTests (TestContext& testCtx) case VK_FILTER_NEAREST: caseName << "_nearest"; break; + case VK_FILTER_LINEAR: caseName << "_linear"; break; + default: break; } @@ -1290,9 +1453,11 @@ TestCaseGroup* create2DSizeTests (TestContext& testCtx) case VK_SAMPLER_MIPMAP_MODE_NEAREST: caseName << "_mipmap_nearest"; break; + case VK_SAMPLER_MIPMAP_MODE_LINEAR: caseName << "_mipmap_linear"; break; + default: break; } @@ -1302,9 +1467,11 @@ TestCaseGroup* create2DSizeTests (TestContext& testCtx) case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: caseName << "_clamp"; break; + case VK_SAMPLER_ADDRESS_MODE_REPEAT: caseName << "_repeat"; break; + default: break; } @@ -1319,7 +1486,8 @@ TestCaseGroup* create2DSizeTests (TestContext& testCtx) filters[magFilterNdx], filters[minFilterNdx], mipmapFilters[mipmapFilterNdx], - wrappingModes[wrappingModeNdx]); + wrappingModes[wrappingModeNdx], + false); tests->addChild(testCase); } @@ -1338,6 +1506,7 @@ TestCaseGroup* create2DTests (TestContext& testCtx) tests->addChild(create2DSizeTests(testCtx)); tests->addChild(create2DFormatTests(testCtx)); + tests->addChild(create2DDerivTests(testCtx)); return tests.release(); } diff --git a/framework/common/tcuInterval.hpp b/framework/common/tcuInterval.hpp index 75c7d65..cc271a1 100644 --- a/framework/common/tcuInterval.hpp +++ b/framework/common/tcuInterval.hpp @@ -70,6 +70,9 @@ public: , 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())) @@ -145,8 +148,6 @@ public: } 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; diff --git a/framework/common/tcuTexture.cpp b/framework/common/tcuTexture.cpp index ed0709e..1d76fb9 100644 --- a/framework/common/tcuTexture.cpp +++ b/framework/common/tcuTexture.cpp @@ -257,36 +257,6 @@ inline deUint32 convertSatRteUint24 (float f) 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 @@ -656,6 +626,36 @@ int getNumUsedChannels (TextureFormat::ChannelOrder order) } } +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) { diff --git a/framework/common/tcuTexture.hpp b/framework/common/tcuTexture.hpp index f401cf6..e73f274 100644 --- a/framework/common/tcuTexture.hpp +++ b/framework/common/tcuTexture.hpp @@ -140,6 +140,7 @@ public: bool isValid (TextureFormat format); int getPixelSize (TextureFormat format); int getNumUsedChannels (TextureFormat::ChannelOrder order); +int getChannelSize (TextureFormat::ChannelType type); /*--------------------------------------------------------------------*//*! * \brief Texture swizzle