Merge vk-gl-cts/vulkan-cts-1.0.2 into vk-gl-cts/vulkan-cts-1.1.0
authorAlexander Galazin <alexander.galazin@arm.com>
Thu, 22 Feb 2018 11:45:50 +0000 (12:45 +0100)
committerAlexander Galazin <alexander.galazin@arm.com>
Thu, 22 Feb 2018 11:45:50 +0000 (12:45 +0100)
Change-Id: I115b3e16d7282ef5f9abeb5bd382f744d891b5e3

1  2 
external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
external/vulkancts/modules/vulkan/ycbcr/vktYCbCrUtil.cpp

index c230969e4a3ae485a15385e51faa15c3ea596dd1,1f9f61821748beb7662769b01ee965f78bb7f915..b154198f40164ee6c140e2fd74d8e6e21fe4b6a7
@@@ -796,1466 -780,5 +796,1466 @@@ void readImageMemory (const vk::DeviceI
        }
  }
  
-                                                       for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
 +// ChannelAccess utilities
 +namespace
 +{
 +
 +//! Extend < 32b signed integer to 32b
 +inline deInt32 signExtend (deUint32 src, int bits)
 +{
 +      const deUint32 signBit = 1u << (bits-1);
 +
 +      src |= ~((src & signBit) - 1);
 +
 +      return (deInt32)src;
 +}
 +
 +deUint32 divRoundUp (deUint32 a, deUint32 b)
 +{
 +      if (a % b == 0)
 +              return a / b;
 +      else
 +              return (a / b) + 1;
 +}
 +
 +// \todo Taken from tcuTexture.cpp
 +// \todo [2011-09-21 pyry] Move to tcutil?
 +template <typename T>
 +inline T convertSatRte (float f)
 +{
 +      // \note Doesn't work for 64-bit types
 +      DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
 +      DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
 +
 +      deInt64 minVal  = std::numeric_limits<T>::min();
 +      deInt64 maxVal  = std::numeric_limits<T>::max();
 +      float   q               = deFloatFrac(f);
 +      deInt64 intVal  = (deInt64)(f-q);
 +
 +      // Rounding.
 +      if (q == 0.5f)
 +      {
 +              if (intVal % 2 != 0)
 +                      intVal++;
 +      }
 +      else if (q > 0.5f)
 +              intVal++;
 +      // else Don't add anything
 +
 +      // Saturate.
 +      intVal = de::max(minVal, de::min(maxVal, intVal));
 +
 +      return (T)intVal;
 +}
 +
 +} // anonymous
 +
 +ChannelAccess::ChannelAccess (tcu::TextureChannelClass        channelClass,
 +                                                        deUint8                                       channelSize,
 +                                                        const tcu::IVec3&                     size,
 +                                                        const tcu::IVec3&                     bitPitch,
 +                                                        void*                                         data,
 +                                                        deUint32                                      bitOffset)
 +      : m_channelClass        (channelClass)
 +      , m_channelSize         (channelSize)
 +      , m_size                        (size)
 +      , m_bitPitch            (bitPitch)
 +
 +      , m_data                        ((deUint8*)data + (bitOffset / 8))
 +      , m_bitOffset           (bitOffset % 8)
 +{
 +}
 +
 +deUint32 ChannelAccess::getChannelUint (const tcu::IVec3& pos) const
 +{
 +      DE_ASSERT(pos[0] < m_size[0]);
 +      DE_ASSERT(pos[1] < m_size[1]);
 +      DE_ASSERT(pos[2] < m_size[2]);
 +
 +      const deInt32                   bitOffset       (m_bitOffset + tcu::dot(m_bitPitch, pos));
 +      const deUint8* const    firstByte       = ((const deUint8*)m_data) + (bitOffset / 8);
 +      const deUint32                  byteCount       = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
 +      const deUint32                  mask            (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
 +      const deUint32                  offset          = bitOffset % 8;
 +      deUint32                                bits            = 0u;
 +
 +      deMemcpy(&bits, firstByte, byteCount);
 +
 +      return (bits >> offset) & mask;
 +}
 +
 +void ChannelAccess::setChannel (const tcu::IVec3& pos, deUint32 x)
 +{
 +      DE_ASSERT(pos[0] < m_size[0]);
 +      DE_ASSERT(pos[1] < m_size[1]);
 +      DE_ASSERT(pos[2] < m_size[2]);
 +
 +      const deInt32   bitOffset       (m_bitOffset + tcu::dot(m_bitPitch, pos));
 +      deUint8* const  firstByte       = ((deUint8*)m_data) + (bitOffset / 8);
 +      const deUint32  byteCount       = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
 +      const deUint32  mask            (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
 +      const deUint32  offset          = bitOffset % 8;
 +
 +      const deUint32  bits            = (x & mask) << offset;
 +      deUint32                oldBits         = 0;
 +
 +      deMemcpy(&oldBits, firstByte, byteCount);
 +
 +      {
 +              const deUint32  newBits = bits | (oldBits & (~(mask << offset)));
 +
 +              deMemcpy(firstByte, &newBits,  byteCount);
 +      }
 +}
 +
 +float ChannelAccess::getChannel (const tcu::IVec3& pos) const
 +{
 +      const deUint32  bits    (getChannelUint(pos));
 +
 +      switch (m_channelClass)
 +      {
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +                      return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u));
 +
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +                      return (float)bits;
 +
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +                      return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u));
 +
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +                      return (float)signExtend(bits, m_channelSize);
 +
 +              case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +                      if (m_channelSize == 32)
 +                              return tcu::Float32(bits).asFloat();
 +                      else
 +                      {
 +                              DE_FATAL("Float type not supported");
 +                              return -1.0f;
 +                      }
 +
 +              default:
 +                      DE_FATAL("Unknown texture channel class");
 +                      return -1.0f;
 +      }
 +}
 +
 +tcu::Interval ChannelAccess::getChannel (const tcu::FloatFormat&      conversionFormat,
 +                                                                               const tcu::IVec3&                      pos) const
 +{
 +      const deUint32  bits    (getChannelUint(pos));
 +
 +      switch (m_channelClass)
 +      {
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +                      return conversionFormat.roundOut(conversionFormat.roundOut((double)bits, false)
 +                                                                                      / conversionFormat.roundOut((double)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)), false), false);
 +
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +                      return conversionFormat.roundOut((double)bits, false);
 +
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +              {
 +                      const tcu::Interval result (conversionFormat.roundOut(conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false)
 +                                                                                                                              / conversionFormat.roundOut((double)((0x1u << (m_channelSize - 1u)) - 1u), false), false));
 +
 +                      return tcu::Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi()));
 +              }
 +
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +                      return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false);
 +
 +              case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +                      if (m_channelSize == 32)
 +                              return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false);
 +                      else
 +                      {
 +                              DE_FATAL("Float type not supported");
 +                              return tcu::Interval();
 +                      }
 +
 +              default:
 +                      DE_FATAL("Unknown texture channel class");
 +                      return tcu::Interval();
 +      }
 +}
 +
 +void ChannelAccess::setChannel (const tcu::IVec3& pos, float x)
 +{
 +      DE_ASSERT(pos[0] < m_size[0]);
 +      DE_ASSERT(pos[1] < m_size[1]);
 +      DE_ASSERT(pos[2] < m_size[2]);
 +
 +      const deUint32  mask    (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
 +
 +      switch (m_channelClass)
 +      {
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +              {
 +                      const deUint32  maxValue        (mask);
 +                      const deUint32  value           (de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue)));
 +                      setChannel(pos, value);
 +                      break;
 +              }
 +
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +              {
 +                      const deInt32   range   ((0x1u << (m_channelSize - 1u)) - 1u);
 +                      const deUint32  value   ((deUint32)de::clamp<deInt32>(convertSatRte<deInt32>(x * (float)range), -range, range));
 +                      setChannel(pos, value);
 +                      break;
 +              }
 +
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +              {
 +                      const deUint32  maxValue        (mask);
 +                      const deUint32  value           (de::min(maxValue, (deUint32)x));
 +                      setChannel(pos, value);
 +                      break;
 +              }
 +
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +              {
 +                      const deInt32   minValue        (-(deInt32)(1u << (m_channelSize - 1u)));
 +                      const deInt32   maxValue        ((deInt32)((1u << (m_channelSize - 1u)) - 1u));
 +                      const deUint32  value           ((deUint32)de::clamp((deInt32)x, minValue, maxValue));
 +                      setChannel(pos, value);
 +                      break;
 +              }
 +
 +              case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +              {
 +                      if (m_channelSize == 32)
 +                      {
 +                              const deUint32  value           = tcu::Float32(x).bits();
 +                              setChannel(pos, value);
 +                      }
 +                      else
 +                              DE_FATAL("Float type not supported");
 +                      break;
 +              }
 +
 +              default:
 +                      DE_FATAL("Unknown texture channel class");
 +      }
 +}
 +
 +ChannelAccess getChannelAccess (MultiPlaneImageData&                          data,
 +                                                              const vk::PlanarFormatDescription&      formatInfo,
 +                                                              const UVec2&                                            size,
 +                                                              int                                                                     channelNdx)
 +{
 +      DE_ASSERT(formatInfo.hasChannelNdx(channelNdx));
 +
 +      const deUint32  planeNdx                        = formatInfo.channels[channelNdx].planeNdx;
 +      const deUint32  valueOffsetBits         = formatInfo.channels[channelNdx].offsetBits;
 +      const deUint32  pixelStrideBytes        = formatInfo.channels[channelNdx].strideBytes;
 +      const deUint32  pixelStrideBits         = pixelStrideBytes * 8;
 +      const deUint8   sizeBits                        = formatInfo.channels[channelNdx].sizeBits;
 +
 +      DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0);
 +      DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0);
 +
 +      deUint32                accessWidth                     = size.x() / formatInfo.planes[planeNdx].widthDivisor;
 +      const deUint32  accessHeight            = size.y() / formatInfo.planes[planeNdx].heightDivisor;
 +      const deUint32  elementSizeBytes        = formatInfo.planes[planeNdx].elementSizeBytes;
 +
 +      const deUint32  rowPitch                        = formatInfo.planes[planeNdx].elementSizeBytes * accessWidth;
 +      const deUint32  rowPitchBits            = rowPitch * 8;
 +
 +      if (pixelStrideBytes != elementSizeBytes)
 +      {
 +              DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0);
 +              accessWidth *= elementSizeBytes/pixelStrideBytes;
 +      }
 +
 +      return ChannelAccess((tcu::TextureChannelClass)formatInfo.channels[channelNdx].type, sizeBits, tcu::IVec3(accessWidth, accessHeight, 1u), tcu::IVec3((int)pixelStrideBits, (int)rowPitchBits, 0), data.getPlanePtr(planeNdx), (deUint32)valueOffsetBits);
 +}
 +
 +bool isXChromaSubsampled (vk::VkFormat format)
 +{
 +      switch (format)
 +      {
 +              case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
 +              case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
 +              case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
 +                      return true;
 +
 +              default:
 +                      return false;
 +      }
 +}
 +
 +bool isYChromaSubsampled (vk::VkFormat format)
 +{
 +      switch (format)
 +      {
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
 +                      return true;
 +
 +              default:
 +                      return false;
 +      }
 +}
 +
 +// \note Used for range expansion
 +tcu::UVec4 getYCbCrBitDepth (vk::VkFormat format)
 +{
 +      switch (format)
 +      {
 +              case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
 +              case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
 +                      return tcu::UVec4(8, 8, 8, 0);
 +
 +              case vk::VK_FORMAT_R10X6_UNORM_PACK16:
 +                      return tcu::UVec4(10, 0, 0, 0);
 +
 +              case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
 +                      return tcu::UVec4(10, 10, 0, 0);
 +
 +              case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
 +                      return tcu::UVec4(10, 10, 10, 10);
 +
 +              case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
 +                      return tcu::UVec4(10, 10, 10, 0);
 +
 +              case vk::VK_FORMAT_R12X4_UNORM_PACK16:
 +                      return tcu::UVec4(12, 0, 0, 0);
 +
 +              case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
 +                      return tcu::UVec4(12, 12, 0, 0);
 +
 +              case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
 +                      return tcu::UVec4(12, 12, 12, 12);
 +
 +              case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
 +              case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
 +                      return tcu::UVec4(16, 16, 16, 0);
 +
 +              default:
 +                      return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>();
 +      }
 +}
 +
 +// \note Taken from explicit lod filtering tests
 +tcu::FloatFormat getYCbCrFilteringPrecision (vk::VkFormat format)
 +{
 +      const tcu::FloatFormat  reallyLow       (0, 0, 6, false, tcu::YES);
 +      const tcu::FloatFormat  low                     (0, 0, 7, false, tcu::YES);
 +      const tcu::FloatFormat  fp16            (-14, 15, 10, false);
 +      const tcu::FloatFormat  fp32            (-126, 127, 23, true);
 +
 +      switch (format)
 +      {
 +              case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
 +              case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
 +              case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
 +              case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
 +              case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
 +              case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
 +              case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
 +                      return reallyLow;
 +
 +              case vk::VK_FORMAT_R8G8B8_UNORM:
 +              case vk::VK_FORMAT_B8G8R8_UNORM:
 +              case vk::VK_FORMAT_R8G8B8A8_UNORM:
 +              case vk::VK_FORMAT_B8G8R8A8_UNORM:
 +              case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
 +              case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
 +              case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
 +                      return low;
 +
 +              case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
 +              case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
 +              case vk::VK_FORMAT_R16G16B16_UNORM:
 +              case vk::VK_FORMAT_R16G16B16A16_UNORM:
 +              case vk::VK_FORMAT_R10X6_UNORM_PACK16:
 +              case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
 +              case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
 +              case vk::VK_FORMAT_R12X4_UNORM_PACK16:
 +              case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
 +              case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
 +              case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
 +                      return fp16;
 +
 +              default:
 +                      DE_FATAL("Precision not defined for format");
 +                      return fp32;
 +      }
 +}
 +
 +// \note Taken from explicit lod filtering tests
 +tcu::FloatFormat getYCbCrConversionPrecision (vk::VkFormat format)
 +{
 +      const tcu::FloatFormat  reallyLow       (0, 0, 8, false, tcu::YES);
 +      const tcu::FloatFormat  fp16            (-14, 15, 10, false);
 +      const tcu::FloatFormat  fp32            (-126, 127, 23, true);
 +
 +      switch (format)
 +      {
 +              case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
 +              case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
 +              case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
 +              case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
 +              case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
 +              case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
 +              case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
 +                      return reallyLow;
 +
 +              case vk::VK_FORMAT_R8G8B8_UNORM:
 +              case vk::VK_FORMAT_B8G8R8_UNORM:
 +              case vk::VK_FORMAT_R8G8B8A8_UNORM:
 +              case vk::VK_FORMAT_B8G8R8A8_UNORM:
 +              case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
 +              case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
 +              case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
 +                      return reallyLow;
 +
 +              case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
 +              case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
 +              case vk::VK_FORMAT_R16G16B16_UNORM:
 +              case vk::VK_FORMAT_R16G16B16A16_UNORM:
 +              case vk::VK_FORMAT_R10X6_UNORM_PACK16:
 +              case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
 +              case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
 +              case vk::VK_FORMAT_R12X4_UNORM_PACK16:
 +              case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
 +              case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
 +              case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
 +                      return fp16;
 +
 +              default:
 +                      DE_FATAL("Precision not defined for format");
 +                      return fp32;
 +      }
 +}
 +
 +deUint32 getYCbCrFormatChannelCount (vk::VkFormat format)
 +{
 +      switch (format)
 +      {
 +              case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
 +              case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
 +              case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
 +              case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
 +              case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
 +              case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
 +              case vk::VK_FORMAT_B8G8R8A8_UNORM:
 +              case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
 +              case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
 +              case vk::VK_FORMAT_R16G16B16A16_UNORM:
 +              case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
 +              case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
 +              case vk::VK_FORMAT_R8G8B8A8_UNORM:
 +                      return 4;
 +
 +              case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
 +              case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
 +              case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
 +              case vk::VK_FORMAT_B8G8R8_UNORM:
 +              case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
 +              case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
 +              case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
 +              case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
 +              case vk::VK_FORMAT_R16G16B16_UNORM:
 +              case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
 +              case vk::VK_FORMAT_R8G8B8_UNORM:
 +                      return 3;
 +
 +              case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
 +              case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
 +                      return 2;
 +
 +              case vk::VK_FORMAT_R10X6_UNORM_PACK16:
 +              case vk::VK_FORMAT_R12X4_UNORM_PACK16:
 +                      return 1;
 +
 +              default:
 +                      DE_FATAL("Unknown number of channels");
 +                      return -1;
 +      }
 +}
 +
 +// YCbCr color conversion utilities
 +namespace
 +{
 +
 +tcu::Interval rangeExpandChroma (vk::VkSamplerYcbcrRange              range,
 +                                                               const tcu::FloatFormat&                conversionFormat,
 +                                                               const deUint32                                 bits,
 +                                                               const tcu::Interval&                   sample)
 +{
 +      const deUint32  values  (0x1u << bits);
 +
 +      switch (range)
 +      {
 +              case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
 +                      return conversionFormat.roundOut(sample - conversionFormat.roundOut(tcu::Interval((double)(0x1u << (bits - 1u)) / (double)((0x1u << bits) - 1u)), false), false);
 +
 +              case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
 +              {
 +                      const tcu::Interval     a                       (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
 +                      const tcu::Interval     dividend        (conversionFormat.roundOut(a - tcu::Interval((double)(128u * (0x1u << (bits - 8u)))), false));
 +                      const tcu::Interval     divisor         ((double)(224u * (0x1u << (bits - 8u))));
 +                      const tcu::Interval     result          (conversionFormat.roundOut(dividend / divisor, false));
 +
 +                      return result;
 +              }
 +
 +              default:
 +                      DE_FATAL("Unknown YCbCrRange");
 +                      return tcu::Interval();
 +      }
 +}
 +
 +tcu::Interval rangeExpandLuma (vk::VkSamplerYcbcrRange                range,
 +                                                         const tcu::FloatFormat&              conversionFormat,
 +                                                         const deUint32                               bits,
 +                                                         const tcu::Interval&                 sample)
 +{
 +      const deUint32  values  (0x1u << bits);
 +
 +      switch (range)
 +      {
 +              case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
 +                      return conversionFormat.roundOut(sample, false);
 +
 +              case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
 +              {
 +                      const tcu::Interval     a                       (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
 +                      const tcu::Interval     dividend        (conversionFormat.roundOut(a - tcu::Interval((double)(16u * (0x1u << (bits - 8u)))), false));
 +                      const tcu::Interval     divisor         ((double)(219u * (0x1u << (bits - 8u))));
 +                      const tcu::Interval     result          (conversionFormat.roundOut(dividend / divisor, false));
 +
 +                      return result;
 +              }
 +
 +              default:
 +                      DE_FATAL("Unknown YCbCrRange");
 +                      return tcu::Interval();
 +      }
 +}
 +
 +tcu::Interval clampMaybe (const tcu::Interval&        x,
 +                                                double                                min,
 +                                                double                                max)
 +{
 +      tcu::Interval result = x;
 +
 +      DE_ASSERT(min <= max);
 +
 +      if (x.lo() < min)
 +              result = result | tcu::Interval(min);
 +
 +      if (x.hi() > max)
 +              result = result | tcu::Interval(max);
 +
 +      return result;
 +}
 +
 +void convertColor (vk::VkSamplerYcbcrModelConversion  colorModel,
 +                                 vk::VkSamplerYcbcrRange                              range,
 +                                 const tcu::FloatFormat&                              conversionFormat,
 +                                 const tcu::UVec4&                                    bitDepth,
 +                                 const tcu::Interval                                  input[4],
 +                                 tcu::Interval                                                output[4])
 +{
 +      switch (colorModel)
 +      {
 +              case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
 +              {
 +                      for (size_t ndx = 0; ndx < 4; ndx++)
 +                              output[ndx] = input[ndx];
 +                      break;
 +              }
 +
 +              case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
 +              {
 +                      output[0] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]), -0.5, 0.5);
 +                      output[1] = clampMaybe(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]), 0.0, 1.0);
 +                      output[2] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]), -0.5, 0.5);
 +                      output[3] = input[3];
 +                      break;
 +              }
 +
 +              case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
 +              {
 +                      const tcu::Interval     y                       (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
 +                      const tcu::Interval     cr                      (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
 +                      const tcu::Interval     cb                      (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
 +
 +                      const tcu::Interval     yClamped        (clampMaybe(y,   0.0, 1.0));
 +                      const tcu::Interval     crClamped       (clampMaybe(cr, -0.5, 0.5));
 +                      const tcu::Interval     cbClamped       (clampMaybe(cb, -0.5, 0.5));
 +
 +                      output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.402 * crClamped, false), false);
 +                      output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.202008 / 0.587) * cbClamped, false), false) - conversionFormat.roundOut((0.419198 / 0.587) * crClamped, false), false);
 +                      output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.772 * cbClamped, false), false);
 +                      output[3] = input[3];
 +                      break;
 +              }
 +
 +              case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
 +              {
 +                      const tcu::Interval     y                       (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
 +                      const tcu::Interval     cr                      (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
 +                      const tcu::Interval     cb                      (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
 +
 +                      const tcu::Interval     yClamped        (clampMaybe(y,   0.0, 1.0));
 +                      const tcu::Interval     crClamped       (clampMaybe(cr, -0.5, 0.5));
 +                      const tcu::Interval     cbClamped       (clampMaybe(cb, -0.5, 0.5));
 +
 +                      output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.5748 * crClamped, false), false);
 +                      output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.13397432 / 0.7152) * cbClamped, false), false) - conversionFormat.roundOut((0.33480248 / 0.7152) * crClamped, false), false);
 +                      output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8556 * cbClamped, false), false);
 +                      output[3] = input[3];
 +                      break;
 +              }
 +
 +              case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
 +              {
 +                      const tcu::Interval     y                       (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
 +                      const tcu::Interval     cr                      (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
 +                      const tcu::Interval     cb                      (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
 +
 +                      const tcu::Interval     yClamped        (clampMaybe(y,   0.0, 1.0));
 +                      const tcu::Interval     crClamped       (clampMaybe(cr, -0.5, 0.5));
 +                      const tcu::Interval     cbClamped       (clampMaybe(cb, -0.5, 0.5));
 +
 +                      output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.4746 * crClamped, false), false);
 +                      output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut(conversionFormat.roundOut(0.11156702 / 0.6780, false) * cbClamped, false), false) - conversionFormat.roundOut(conversionFormat.roundOut(0.38737742 / 0.6780, false) * crClamped, false), false);
 +                      output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8814 * cbClamped, false), false);
 +                      output[3] = input[3];
 +                      break;
 +              }
 +
 +              default:
 +                      DE_FATAL("Unknown YCbCrModel");
 +      }
 +
 +      if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY)
 +      {
 +              for (int ndx = 0; ndx < 3; ndx++)
 +                      output[ndx] = clampMaybe(output[ndx], 0.0, 1.0);
 +      }
 +}
 +
 +int mirror (int coord)
 +{
 +      return coord >= 0 ? coord : -(1 + coord);
 +}
 +
 +int imod (int a, int b)
 +{
 +      int m = a % b;
 +      return m < 0 ? m + b : m;
 +}
 +
 +tcu::Interval frac (const tcu::Interval& x)
 +{
 +      if (x.hi() - x.lo() >= 1.0)
 +              return tcu::Interval(0.0, 1.0);
 +      else
 +      {
 +              const tcu::Interval ret (deFrac(x.lo()), deFrac(x.hi()));
 +
 +              return ret;
 +      }
 +}
 +
 +tcu::Interval calculateUV (const tcu::FloatFormat&    coordFormat,
 +                                                 const tcu::Interval&         st,
 +                                                 const int                            size)
 +{
 +      return coordFormat.roundOut(coordFormat.roundOut(st, false) * tcu::Interval((double)size), false);
 +}
 +
 +tcu::IVec2 calculateNearestIJRange (const tcu::FloatFormat&   coordFormat,
 +                                                                  const tcu::Interval&        uv)
 +{
 +      const tcu::Interval     ij      (coordFormat.roundOut(coordFormat.roundOut(uv, false) - tcu::Interval(0.5), false));
 +
 +      return tcu::IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1)));
 +}
 +
 +// Calculate range of pixel coordinates that can be used as lower coordinate for linear sampling
 +tcu::IVec2 calculateLinearIJRange (const tcu::FloatFormat&    coordFormat,
 +                                                                 const tcu::Interval&         uv)
 +{
 +      const tcu::Interval     ij      (coordFormat.roundOut(uv - tcu::Interval(0.5), false));
 +
 +      return tcu::IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi()));
 +}
 +
 +tcu::Interval calculateAB (const deUint32             subTexelPrecisionBits,
 +                                                 const tcu::Interval& uv,
 +                                                 int                                  ij)
 +{
 +      const deUint32          subdivisions    = 0x1u << subTexelPrecisionBits;
 +      const tcu::Interval     ab                              (frac((uv - 0.5) & tcu::Interval((double)ij, (double)(ij + 1))));
 +      const tcu::Interval     gridAB                  (ab * tcu::Interval(subdivisions));
 +      const tcu::Interval     rounded                 (de::max(deFloor(gridAB.lo()) / subdivisions, 0.0) , de::min(deCeil(gridAB.hi()) / subdivisions, 1.0));
 +
 +      return rounded;
 +}
 +
 +tcu::Interval lookupWrapped (const ChannelAccess&             access,
 +                                                       const tcu::FloatFormat&        conversionFormat,
 +                                                       vk::VkSamplerAddressMode       addressModeU,
 +                                                       vk::VkSamplerAddressMode       addressModeV,
 +                                                       const tcu::IVec2&                      coord)
 +{
 +      return access.getChannel(conversionFormat,
 +                                                       tcu::IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0));
 +}
 +
 +tcu::Interval linearInterpolate (const tcu::FloatFormat&      filteringFormat,
 +                                                               const tcu::Interval&           a,
 +                                                               const tcu::Interval&           b,
 +                                                               const tcu::Interval&           p00,
 +                                                               const tcu::Interval&           p10,
 +                                                               const tcu::Interval&           p01,
 +                                                               const tcu::Interval&           p11)
 +{
 +      const tcu::Interval     p[4] =
 +      {
 +              p00,
 +              p10,
 +              p01,
 +              p11
 +      };
 +      tcu::Interval           result  (0.0);
 +
 +      for (size_t ndx = 0; ndx < 4; ndx++)
 +      {
 +              const tcu::Interval     weightA (filteringFormat.roundOut((ndx % 2) == 0 ? (1.0 - a) : a, false));
 +              const tcu::Interval     weightB (filteringFormat.roundOut((ndx / 2) == 0 ? (1.0 - b) : b, false));
 +              const tcu::Interval     weight  (filteringFormat.roundOut(weightA * weightB, false));
 +
 +              result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false);
 +      }
 +
 +      return result;
 +}
 +
 +tcu::Interval calculateImplicitChromaUV (const tcu::FloatFormat&      coordFormat,
 +                                                                               vk::VkChromaLocation           offset,
 +                                                                               const tcu::Interval&           uv)
 +{
 +      if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
 +              return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false);
 +      else
 +              return coordFormat.roundOut(0.5 * uv, false);
 +}
 +
 +tcu::Interval linearSample (const ChannelAccess&              access,
 +                                                  const tcu::FloatFormat&             conversionFormat,
 +                                                  const tcu::FloatFormat&             filteringFormat,
 +                                                  vk::VkSamplerAddressMode    addressModeU,
 +                                                  vk::VkSamplerAddressMode    addressModeV,
 +                                                  const tcu::IVec2&                   coord,
 +                                                  const tcu::Interval&                a,
 +                                                  const tcu::Interval&                b)
 +{
 +      return linearInterpolate(filteringFormat, a, b,
 +                                                                      lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 0)),
 +                                                                      lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 0)),
 +                                                                      lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 1)),
 +                                                                      lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 1)));
 +}
 +
 +tcu::Interval reconstructLinearXChromaSample (const tcu::FloatFormat& filteringFormat,
 +                                                                                        const tcu::FloatFormat&       conversionFormat,
 +                                                                                        vk::VkChromaLocation          offset,
 +                                                                                        vk::VkSamplerAddressMode      addressModeU,
 +                                                                                        vk::VkSamplerAddressMode      addressModeV,
 +                                                                                        const ChannelAccess&          access,
 +                                                                                        int                                           i,
 +                                                                                        int                                           j)
 +{
 +      const int subI  = divFloor(i, 2);
 +
 +      if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
 +      {
 +              if (i % 2 == 0)
 +                      return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j));
 +              else
 +              {
 +                      const tcu::Interval     a       (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
 +                      const tcu::Interval     b       (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
 +
 +                      return filteringFormat.roundOut(a + b, false);
 +              }
 +      }
 +      else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT)
 +      {
 +              if (i % 2 == 0)
 +              {
 +                      const tcu::Interval     a       (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI - 1, j)), false));
 +                      const tcu::Interval     b       (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
 +
 +                      return filteringFormat.roundOut(a + b, false);
 +              }
 +              else
 +              {
 +                      const tcu::Interval     a       (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
 +                      const tcu::Interval     b       (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
 +
 +                      return filteringFormat.roundOut(a + b, false);
 +              }
 +      }
 +      else
 +      {
 +              DE_FATAL("Unknown sample location");
 +              return tcu::Interval();
 +      }
 +}
 +
 +tcu::Interval reconstructLinearXYChromaSample (const tcu::FloatFormat&        filteringFormat,
 +                                                                                const tcu::FloatFormat&               conversionFormat,
 +                                                                                vk::VkChromaLocation                  xOffset,
 +                                                                                vk::VkChromaLocation                  yOffset,
 +                                                                                vk::VkSamplerAddressMode              addressModeU,
 +                                                                                vk::VkSamplerAddressMode              addressModeV,
 +                                                                                const ChannelAccess&                  access,
 +                                                                                int                                                   i,
 +                                                                                int                                                   j)
 +{
 +      const int               subI    = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
 +                                                      ? divFloor(i, 2)
 +                                                      : (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2));
 +      const int               subJ    = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
 +                                                      ? divFloor(j, 2)
 +                                                      : (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2));
 +
 +      const double    a               = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
 +                                                      ? (i % 2 == 0 ? 0.0 : 0.5)
 +                                                      : (i % 2 == 0 ? 0.25 : 0.75);
 +      const double    b               = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
 +                                                      ? (j % 2 == 0 ? 0.0 : 0.5)
 +                                                      : (j % 2 == 0 ? 0.25 : 0.75);
 +
 +      return linearInterpolate(filteringFormat, a, b,
 +                                                              lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ)),
 +                                                              lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ)),
 +                                                              lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ + 1)),
 +                                                              lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ + 1)));
 +}
 +
 +const ChannelAccess& swizzle (vk::VkComponentSwizzle  swizzle,
 +                                                        const ChannelAccess&          identityPlane,
 +                                                        const ChannelAccess&          rPlane,
 +                                                        const ChannelAccess&          gPlane,
 +                                                        const ChannelAccess&          bPlane,
 +                                                        const ChannelAccess&          aPlane)
 +{
 +      switch (swizzle)
 +      {
 +              case vk::VK_COMPONENT_SWIZZLE_IDENTITY: return identityPlane;
 +              case vk::VK_COMPONENT_SWIZZLE_R:                return rPlane;
 +              case vk::VK_COMPONENT_SWIZZLE_G:                return gPlane;
 +              case vk::VK_COMPONENT_SWIZZLE_B:                return bPlane;
 +              case vk::VK_COMPONENT_SWIZZLE_A:                return aPlane;
 +
 +              default:
 +                      DE_FATAL("Unsupported swizzle");
 +                      return identityPlane;
 +      }
 +}
 +
 +} // anonymous
 +
 +int wrap (vk::VkSamplerAddressMode    addressMode,
 +                int                                           coord,
 +                int                                           size)
 +{
 +      switch (addressMode)
 +      {
 +              case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
 +                      return (size - 1) - mirror(imod(coord, 2 * size) - size);
 +
 +              case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT:
 +                      return imod(coord, size);
 +
 +              case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
 +                      return de::clamp(coord, 0, size - 1);
 +
 +              case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
 +                      return de::clamp(mirror(coord), 0, size - 1);
 +
 +              default:
 +                      DE_FATAL("Unknown wrap mode");
 +                      return ~0;
 +      }
 +}
 +
 +int divFloor (int a, int b)
 +{
 +      if (a % b == 0)
 +              return a / b;
 +      else if (a > 0)
 +              return a / b;
 +      else
 +              return (a / b) - 1;
 +}
 +
 +void calculateBounds (const ChannelAccess&                                    rPlane,
 +                                        const ChannelAccess&                                  gPlane,
 +                                        const ChannelAccess&                                  bPlane,
 +                                        const ChannelAccess&                                  aPlane,
 +                                        const UVec4&                                                  bitDepth,
 +                                        const vector<Vec2>&                                   sts,
 +                                        const FloatFormat&                                    filteringFormat,
 +                                        const FloatFormat&                                    conversionFormat,
 +                                        const deUint32                                                subTexelPrecisionBits,
 +                                        vk::VkFilter                                                  filter,
 +                                        vk::VkSamplerYcbcrModelConversion             colorModel,
 +                                        vk::VkSamplerYcbcrRange                               range,
 +                                        vk::VkFilter                                                  chromaFilter,
 +                                        vk::VkChromaLocation                                  xChromaOffset,
 +                                        vk::VkChromaLocation                                  yChromaOffset,
 +                                        const vk::VkComponentMapping&                 componentMapping,
 +                                        bool                                                                  explicitReconstruction,
 +                                        vk::VkSamplerAddressMode                              addressModeU,
 +                                        vk::VkSamplerAddressMode                              addressModeV,
 +                                        std::vector<Vec4>&                                    minBounds,
 +                                        std::vector<Vec4>&                                    maxBounds,
 +                                        std::vector<Vec4>&                                    uvBounds,
 +                                        std::vector<IVec4>&                                   ijBounds)
 +{
 +      const FloatFormat               highp                   (-126, 127, 23, true,
 +                                                                                       tcu::MAYBE,    // subnormals
 +                                                                                       tcu::YES,              // infinities
 +                                                                                       tcu::MAYBE);   // NaN
 +      const FloatFormat               coordFormat             (-32, 32, 16, true);
 +      const ChannelAccess&    rAccess                 (swizzle(componentMapping.r, rPlane, rPlane, gPlane, bPlane, aPlane));
 +      const ChannelAccess&    gAccess                 (swizzle(componentMapping.g, gPlane, rPlane, gPlane, bPlane, aPlane));
 +      const ChannelAccess&    bAccess                 (swizzle(componentMapping.b, bPlane, rPlane, gPlane, bPlane, aPlane));
 +      const ChannelAccess&    aAccess                 (swizzle(componentMapping.a, aPlane, rPlane, gPlane, bPlane, aPlane));
 +
 +      const bool                              subsampledX             = gAccess.getSize().x() > rAccess.getSize().x();
 +      const bool                              subsampledY             = gAccess.getSize().y() > rAccess.getSize().y();
 +
 +      minBounds.resize(sts.size(), Vec4(TCU_INFINITY));
 +      maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY));
 +
 +      uvBounds.resize(sts.size(), Vec4(TCU_INFINITY, -TCU_INFINITY, TCU_INFINITY, -TCU_INFINITY));
 +      ijBounds.resize(sts.size(), IVec4(0x7FFFFFFF, -1 -0x7FFFFFFF, 0x7FFFFFFF, -1 -0x7FFFFFFF));
 +
 +      // Chroma plane sizes must match
 +      DE_ASSERT(rAccess.getSize() == bAccess.getSize());
 +
 +      // Luma plane sizes must match
 +      DE_ASSERT(gAccess.getSize() == aAccess.getSize());
 +
 +      // Luma plane size must match chroma plane or be twice as big
 +      DE_ASSERT(rAccess.getSize().x() == gAccess.getSize().x() || 2 * rAccess.getSize().x() == gAccess.getSize().x());
 +      DE_ASSERT(rAccess.getSize().y() == gAccess.getSize().y() || 2 * rAccess.getSize().y() == gAccess.getSize().y());
 +
 +      for (size_t ndx = 0; ndx < sts.size(); ndx++)
 +      {
 +              const Vec2      st              (sts[ndx]);
 +              Interval        bounds[4];
 +
 +              const Interval  u       (calculateUV(coordFormat, st[0], gAccess.getSize().x()));
 +              const Interval  v       (calculateUV(coordFormat, st[1], gAccess.getSize().y()));
 +
 +              uvBounds[ndx][0] = (float)u.lo();
 +              uvBounds[ndx][1] = (float)u.hi();
 +
 +              uvBounds[ndx][2] = (float)v.lo();
 +              uvBounds[ndx][3] = (float)v.hi();
 +
 +              if (filter == vk::VK_FILTER_NEAREST)
 +              {
 +                      const IVec2     iRange  (calculateNearestIJRange(coordFormat, u));
 +                      const IVec2     jRange  (calculateNearestIJRange(coordFormat, v));
 +
 +                      ijBounds[ndx][0] = iRange[0];
 +                      ijBounds[ndx][1] = iRange[1];
 +
 +                      ijBounds[ndx][2] = jRange[0];
 +                      ijBounds[ndx][3] = jRange[1];
 +
 +                      for (int j = jRange.x(); j <= jRange.y(); j++)
 +                      for (int i = iRange.x(); i <= iRange.y(); i++)
 +                      {
 +                              const Interval  gValue  (lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
 +                              const Interval  aValue  (lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
 +
 +                              if (subsampledX || subsampledY)
 +                              {
 +                                      if (explicitReconstruction)
 +                                      {
 +                                              if (chromaFilter == vk::VK_FILTER_NEAREST)
 +                                              {
 +                                                      // Nearest, Reconstructed chroma with explicit nearest filtering
 +                                                      const int               subI            = subsampledX ? i / 2 : i;
 +                                                      const int               subJ            = subsampledY ? j / 2 : j;
 +                                                      const Interval  srcColor[]      =
 +                                                      {
 +                                                              lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
 +                                                              gValue,
 +                                                              lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
 +                                                              aValue
 +                                                      };
 +                                                      Interval                dstColor[4];
 +
 +                                                      convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                      for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                              bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                              }
 +                                              else if (chromaFilter == vk::VK_FILTER_LINEAR)
 +                                              {
 +                                                      if (subsampledX && subsampledY)
 +                                                      {
 +                                                              // Nearest, Reconstructed both chroma samples with explicit linear filtering
 +                                                              const Interval  rValue  (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j));
 +                                                              const Interval  bValue  (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j));
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      rValue,
 +                                                                      gValue,
 +                                                                      bValue,
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                                      else if (subsampledX)
 +                                                      {
 +                                                              // Nearest, Reconstructed x chroma samples with explicit linear filtering
 +                                                              const Interval  rValue  (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j));
 +                                                              const Interval  bValue  (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j));
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      rValue,
 +                                                                      gValue,
 +                                                                      bValue,
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                                      else
 +                                                              DE_FATAL("Unexpected chroma reconstruction");
 +                                              }
 +                                              else
 +                                                      DE_FATAL("Unknown filter");
 +                                      }
 +                                      else
 +                                      {
 +                                              const Interval  chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
 +                                              const Interval  chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
 +
 +                                              if (chromaFilter == vk::VK_FILTER_NEAREST)
 +                                              {
 +                                                      // Nearest, reconstructed chroma samples with implicit nearest filtering
 +                                                      const IVec2     chromaIRange    (subsampledX ? calculateNearestIJRange(coordFormat, chromaU) : IVec2(i, i));
 +                                                      const IVec2     chromaJRange    (subsampledY ? calculateNearestIJRange(coordFormat, chromaV) : IVec2(j, j));
 +
 +                                                      for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
-                                                       for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
++                                                      for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
 +                                                      {
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
 +                                                                      gValue,
 +                                                                      lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                              }
 +                                              else if (chromaFilter == vk::VK_FILTER_LINEAR)
 +                                              {
 +                                                      // Nearest, reconstructed chroma samples with implicit linear filtering
 +                                                      const IVec2     chromaIRange    (subsampledX ? calculateLinearIJRange(coordFormat, chromaU) : IVec2(i, i));
 +                                                      const IVec2     chromaJRange    (subsampledY ? calculateLinearIJRange(coordFormat, chromaV) : IVec2(j, j));
 +
 +                                                      for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
-                                                       for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
++                                                      for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
 +                                                      {
 +                                                              const Interval  chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
 +                                                              const Interval  chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
 +
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
 +                                                                      gValue,
 +                                                                      linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                              }
 +                                              else
 +                                                      DE_FATAL("Unknown filter");
 +                                      }
 +                              }
 +                              else
 +                              {
 +                                      // Linear, no chroma subsampling
 +                                      const Interval  srcColor[]      =
 +                                      {
 +                                              lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
 +                                              gValue,
 +                                              lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
 +                                              aValue
 +                                      };
 +                                      Interval dstColor[4];
 +
 +                                      convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                      for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                              bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                              }
 +                      }
 +              }
 +              else if (filter == vk::VK_FILTER_LINEAR)
 +              {
 +                      const IVec2     iRange  (calculateLinearIJRange(coordFormat, u));
 +                      const IVec2     jRange  (calculateLinearIJRange(coordFormat, v));
 +
 +                      ijBounds[ndx][0] = iRange[0];
 +                      ijBounds[ndx][1] = iRange[1];
 +
 +                      ijBounds[ndx][2] = jRange[0];
 +                      ijBounds[ndx][3] = jRange[1];
 +
 +                      for (int j = jRange.x(); j <= jRange.y(); j++)
 +                      for (int i = iRange.x(); i <= iRange.y(); i++)
 +                      {
 +                              const Interval  lumaA           (calculateAB(subTexelPrecisionBits, u, i));
 +                              const Interval  lumaB           (calculateAB(subTexelPrecisionBits, v, j));
 +
 +                              const Interval  gValue          (linearSample(gAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
 +                              const Interval  aValue          (linearSample(aAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
 +
 +                              if (subsampledX || subsampledY)
 +                              {
 +                                      if (explicitReconstruction)
 +                                      {
 +                                              if (chromaFilter == vk::VK_FILTER_NEAREST)
 +                                              {
 +                                                      const Interval  srcColor[]      =
 +                                                      {
 +                                                              linearInterpolate(filteringFormat, lumaA, lumaB,
 +                                                                                                                              lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
 +                                                                                                                              lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
 +                                                                                                                              lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
 +                                                                                                                              lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
 +                                                              gValue,
 +                                                              linearInterpolate(filteringFormat, lumaA, lumaB,
 +                                                                                                                              lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
 +                                                                                                                              lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
 +                                                                                                                              lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
 +                                                                                                                              lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
 +                                                              aValue
 +                                                      };
 +                                                      Interval                dstColor[4];
 +
 +                                                      convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                      for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                              bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                              }
 +                                              else if (chromaFilter == vk::VK_FILTER_LINEAR)
 +                                              {
 +                                                      if (subsampledX && subsampledY)
 +                                                      {
 +                                                              // Linear, Reconstructed xx chroma samples with explicit linear filtering
 +                                                              const Interval  rValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j),
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
 +                                                              const Interval  bValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j),
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
 +                                                                                                                                                      reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      rValue,
 +                                                                      gValue,
 +                                                                      bValue,
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +
 +                                                      }
 +                                                      else if (subsampledX)
 +                                                      {
 +                                                              // Linear, Reconstructed x chroma samples with explicit linear filtering
 +                                                              const Interval  rValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j),
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
 +                                                              const Interval  bValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j),
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
 +                                                                                                                                                      reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      rValue,
 +                                                                      gValue,
 +                                                                      bValue,
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                                      else
 +                                                              DE_FATAL("Unknown subsampling config");
 +                                              }
 +                                              else
 +                                                      DE_FATAL("Unknown chroma filter");
 +                                      }
 +                                      else
 +                                      {
 +                                              const Interval  chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
 +                                              const Interval  chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
 +
 +                                              if (chromaFilter == vk::VK_FILTER_NEAREST)
 +                                              {
 +                                                      const IVec2     chromaIRange    (calculateNearestIJRange(coordFormat, chromaU));
 +                                                      const IVec2     chromaJRange    (calculateNearestIJRange(coordFormat, chromaV));
 +
 +                                                      for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
-                                                       for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
++                                                      for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
 +                                                      {
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
 +                                                                      gValue,
 +                                                                      lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
 +                                                                      aValue
 +                                                              };
 +                                                              Interval        dstColor[4];
 +
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                              }
 +                                              else if (chromaFilter == vk::VK_FILTER_LINEAR)
 +                                              {
 +                                                      const IVec2     chromaIRange    (calculateNearestIJRange(coordFormat, chromaU));
 +                                                      const IVec2     chromaJRange    (calculateNearestIJRange(coordFormat, chromaV));
 +
 +                                                      for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
++                                                      for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
 +                                                      {
 +                                                              const Interval  chromaA         (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
 +                                                              const Interval  chromaB         (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
 +
 +                                                              const Interval  rValue          (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
 +                                                              const Interval  bValue          (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
 +
 +                                                              const Interval  srcColor[]      =
 +                                                              {
 +                                                                      rValue,
 +                                                                      gValue,
 +                                                                      bValue,
 +                                                                      aValue
 +                                                              };
 +                                                              Interval                dstColor[4];
 +                                                              convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                                              for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                                                      bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                                                      }
 +                                              }
 +                                              else
 +                                                      DE_FATAL("Unknown chroma filter");
 +                                      }
 +                              }
 +                              else
 +                              {
 +                                      const Interval  chromaA         (lumaA);
 +                                      const Interval  chromaB         (lumaB);
 +                                      const Interval  rValue          (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
 +                                      const Interval  bValue          (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
 +                                      const Interval  srcColor[]      =
 +                                      {
 +                                              rValue,
 +                                              gValue,
 +                                              bValue,
 +                                              aValue
 +                                      };
 +                                      Interval dstColor[4];
 +
 +                                      convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
 +
 +                                      for (size_t compNdx = 0; compNdx < 4; compNdx++)
 +                                              bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
 +                              }
 +                      }
 +              }
 +              else
 +                      DE_FATAL("Unknown filter");
 +
 +              minBounds[ndx] = Vec4((float)bounds[0].lo(), (float)bounds[1].lo(), (float)bounds[2].lo(), (float)bounds[3].lo());
 +              maxBounds[ndx] = Vec4((float)bounds[0].hi(), (float)bounds[1].hi(), (float)bounds[2].hi(), (float)bounds[3].hi());
 +      }
 +}
 +
 +
  } // ycbcr
  } // vkt