Improve texture border color handling.
authorJarkko Pöyry <jpoyry@google.com>
Tue, 31 Mar 2015 03:28:07 +0000 (20:28 -0700)
committerJarkko Pöyry <jpoyry@google.com>
Fri, 24 Apr 2015 23:06:16 +0000 (16:06 -0700)
- Apply border color only to active channels.
- Clamp border color to format range as specified in GL.
- Support int and uint border colors.
- Convert border color of sRGB formats to linear.
- Support border color in texture compare verifier.

Change-Id: Id191c605e61aa513a1aa65c3009dabda72c81163

framework/common/tcuTexCompareVerifier.cpp
framework/common/tcuTexLookupVerifier.cpp
framework/common/tcuTexture.cpp
framework/common/tcuTexture.hpp
framework/common/tcuTextureUtil.cpp
framework/common/tcuTextureUtil.hpp

index 9806c70..9f10295 100644 (file)
@@ -44,11 +44,6 @@ static bool isSamplerSupported (const Sampler& sampler)
 }
 #endif // DE_DEBUG
 
-static inline float lookupDepth (const ConstPixelBufferAccess& access, int i, int j, int k = 0)
-{
-       return access.getPixDepth(i, j, k);
-}
-
 struct CmpResultSet
 {
        bool    isTrue;
@@ -131,6 +126,27 @@ static inline bool isResultInSet (const CmpResultSet resultSet, const float resu
                   (resultSet.isFalse   && de::inRange(0.0f, minR, maxR));
 }
 
+static inline bool coordsInBounds (const ConstPixelBufferAccess& access, int x, int y, int z)
+{
+       return de::inBounds(x, 0, access.getWidth()) && de::inBounds(y, 0, access.getHeight()) && de::inBounds(z, 0, access.getDepth());
+}
+
+static float lookupDepth (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k)
+{
+       if (coordsInBounds(access, i, j, k))
+               return access.getPixDepth(i, j, k);
+       else
+               return sampleTextureBorder<float>(access.getFormat(), sampler).x();
+}
+
+// lookup depth value at a point that is guaranteed to not sample border such as cube map faces.
+static float lookupDepthNoBorder (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k = 0)
+{
+       DE_UNREF(sampler);
+       DE_ASSERT(coordsInBounds(access, i, j, k));
+       return access.getPixDepth(i, j, k);
+}
+
 // Values are in order (0,0), (1,0), (0,1), (1,1)
 static float bilinearInterpolate (const Vec4& values, const float x, const float y)
 {
@@ -543,7 +559,7 @@ static bool isNearestCompareResultValid (const ConstPixelBufferAccess&              level,
                {
                        const int                       x               = wrap(sampler.wrapS, i, level.getWidth());
                        const int                       y               = wrap(sampler.wrapT, j, level.getHeight());
-                       const float                     depth   = lookupDepth(level, x, y, coordZ);
+                       const float                     depth   = lookupDepth(level, sampler, x, y, coordZ);
                        const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
 
                        if (isResultInSet(resSet, result, prec.resultBits))
@@ -593,10 +609,10 @@ static bool isLinearCompareResultValid (const ConstPixelBufferAccess&             level,
                        const float     minB    = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
                        const float     maxB    = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
 
-                       const Vec4      depths  (lookupDepth(level, x0, y0, coordZ),
-                                                                lookupDepth(level, x1, y0, coordZ),
-                                                                lookupDepth(level, x0, y1, coordZ),
-                                                                lookupDepth(level, x1, y1, coordZ));
+                       const Vec4      depths  (lookupDepth(level, sampler, x0, y0, coordZ),
+                                                                lookupDepth(level, sampler, x1, y0, coordZ),
+                                                                lookupDepth(level, sampler, x0, y1, coordZ),
+                                                                lookupDepth(level, sampler, x1, y1, coordZ));
 
                        if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
                                return true;
@@ -657,13 +673,13 @@ static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAcces
        {
                for (int i0 = minI0; i0 <= maxI0; i0++)
                {
-                       const float     depth0  = lookupDepth(level0, wrap(sampler.wrapS, i0, w0), wrap(sampler.wrapT, j0, h0), coordZ);
+                       const float     depth0  = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), wrap(sampler.wrapT, j0, h0), coordZ);
 
                        for (int j1 = minJ1; j1 <= maxJ1; j1++)
                        {
                                for (int i1 = minI1; i1 <= maxI1; i1++)
                                {
-                                       const float     depth1  = lookupDepth(level1, wrap(sampler.wrapS, i1, w1), wrap(sampler.wrapT, j1, h1), coordZ);
+                                       const float     depth1  = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), wrap(sampler.wrapT, j1, h1), coordZ);
 
                                        if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
                                                return true;
@@ -726,10 +742,10 @@ static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess
                                const int       y0              = wrap(sampler.wrapT, j0  , h0);
                                const int       y1              = wrap(sampler.wrapT, j0+1, h0);
 
-                               depths0[0] = lookupDepth(level0, x0, y0, coordZ);
-                               depths0[1] = lookupDepth(level0, x1, y0, coordZ);
-                               depths0[2] = lookupDepth(level0, x0, y1, coordZ);
-                               depths0[3] = lookupDepth(level0, x1, y1, coordZ);
+                               depths0[0] = lookupDepth(level0, sampler, x0, y0, coordZ);
+                               depths0[1] = lookupDepth(level0, sampler, x1, y0, coordZ);
+                               depths0[2] = lookupDepth(level0, sampler, x0, y1, coordZ);
+                               depths0[3] = lookupDepth(level0, sampler, x1, y1, coordZ);
                        }
 
                        for (int j1 = minJ1; j1 <= maxJ1; j1++)
@@ -748,10 +764,10 @@ static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess
                                                const int       y0              = wrap(sampler.wrapT, j1  , h1);
                                                const int       y1              = wrap(sampler.wrapT, j1+1, h1);
 
-                                               depths1[0] = lookupDepth(level1, x0, y0, coordZ);
-                                               depths1[1] = lookupDepth(level1, x1, y0, coordZ);
-                                               depths1[2] = lookupDepth(level1, x0, y1, coordZ);
-                                               depths1[3] = lookupDepth(level1, x1, y1, coordZ);
+                                               depths1[0] = lookupDepth(level1, sampler, x0, y0, coordZ);
+                                               depths1[1] = lookupDepth(level1, sampler, x1, y0, coordZ);
+                                               depths1[2] = lookupDepth(level1, sampler, x0, y1, coordZ);
+                                               depths1[3] = lookupDepth(level1, sampler, x1, y1, coordZ);
                                        }
 
                                        if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
@@ -913,10 +929,10 @@ static bool isSeamplessLinearMipmapLinearCompareResultValid (const TextureCubeVi
                                if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
                                        return true;
 
-                               depths0[0] = lookupDepth(faces0[c00.face], c00.s, c00.t);
-                               depths0[1] = lookupDepth(faces0[c10.face], c10.s, c10.t);
-                               depths0[2] = lookupDepth(faces0[c01.face], c01.s, c01.t);
-                               depths0[3] = lookupDepth(faces0[c11.face], c11.s, c11.t);
+                               depths0[0] = lookupDepthNoBorder(faces0[c00.face], sampler, c00.s, c00.t);
+                               depths0[1] = lookupDepthNoBorder(faces0[c10.face], sampler, c10.s, c10.t);
+                               depths0[2] = lookupDepthNoBorder(faces0[c01.face], sampler, c01.s, c01.t);
+                               depths0[3] = lookupDepthNoBorder(faces0[c11.face], sampler, c11.s, c11.t);
                        }
 
                        for (int j1 = minJ1; j1 <= maxJ1; j1++)
@@ -938,10 +954,10 @@ static bool isSeamplessLinearMipmapLinearCompareResultValid (const TextureCubeVi
                                                if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
                                                        return true;
 
-                                               depths1[0] = lookupDepth(faces1[c00.face], c00.s, c00.t);
-                                               depths1[1] = lookupDepth(faces1[c10.face], c10.s, c10.t);
-                                               depths1[2] = lookupDepth(faces1[c01.face], c01.s, c01.t);
-                                               depths1[3] = lookupDepth(faces1[c11.face], c11.s, c11.t);
+                                               depths1[0] = lookupDepthNoBorder(faces1[c00.face], sampler, c00.s, c00.t);
+                                               depths1[1] = lookupDepthNoBorder(faces1[c10.face], sampler, c10.s, c10.t);
+                                               depths1[2] = lookupDepthNoBorder(faces1[c01.face], sampler, c01.s, c01.t);
+                                               depths1[3] = lookupDepthNoBorder(faces1[c11.face], sampler, c11.s, c11.t);
                                        }
 
 
@@ -1029,10 +1045,10 @@ static bool isSeamlessLinearCompareResultValid (const TextureCubeView&          texture,
                        const float     maxB    = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
 
                        Vec4 depths;
-                       depths[0] = lookupDepth(faces[c00.face], c00.s, c00.t);
-                       depths[1] = lookupDepth(faces[c10.face], c10.s, c10.t);
-                       depths[2] = lookupDepth(faces[c01.face], c01.s, c01.t);
-                       depths[3] = lookupDepth(faces[c11.face], c11.s, c11.t);
+                       depths[0] = lookupDepthNoBorder(faces[c00.face], sampler, c00.s, c00.t);
+                       depths[1] = lookupDepthNoBorder(faces[c10.face], sampler, c10.s, c10.t);
+                       depths[2] = lookupDepthNoBorder(faces[c01.face], sampler, c01.s, c01.t);
+                       depths[3] = lookupDepthNoBorder(faces[c11.face], sampler, c11.s, c11.t);
 
                        if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
                                return true;
@@ -1246,7 +1262,7 @@ static bool isGatherOffsetsCompareResultValid (const ConstPixelBufferAccess&      tex
                                // offNdx-th coordinate offset and then wrapped.
                                const int                       x               = wrap(sampler.wrapS, i+offsets[offNdx].x(), w);
                                const int                       y               = wrap(sampler.wrapT, j+offsets[offNdx].y(), h);
-                               const float                     depth   = lookupDepth(texture, x, y, coordZ);
+                               const float                     depth   = lookupDepth(texture, sampler, x, y, coordZ);
                                const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
 
                                if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
@@ -1344,7 +1360,7 @@ static bool isGatherCompareResultValid (const TextureCubeView&            texture,
                                if (c.face == CUBEFACE_LAST)
                                        return true;
 
-                               const float                     depth   = lookupDepth(faces[c.face], c.s, c.t);
+                               const float                     depth   = lookupDepthNoBorder(faces[c.face], sampler, c.s, c.t);
                                const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
 
                                if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
index 89aa55b..e7d7ccb 100644 (file)
@@ -58,20 +58,21 @@ inline Vector<ScalarType, 4> lookup (const ConstPixelBufferAccess& access, const
        if (coordsInBounds(access, i, j, k))
                return access.getPixelT<ScalarType>(i, j, k);
        else
-               return sampler.borderColor.cast<ScalarType>();
+               return sampleTextureBorder<ScalarType>(access.getFormat(), sampler);
 }
 
 template<>
 inline Vector<float, 4> lookup (const ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k)
 {
        // Specialization for float lookups: sRGB conversion is performed as specified in format.
+       Vec4 p;
+
        if (coordsInBounds(access, i, j, k))
-       {
-               const Vec4 p = access.getPixel(i, j, k);
-               return isSRGB(access.getFormat()) ? sRGBToLinear(p) : p;
-       }
+               p = access.getPixel(i, j, k);
        else
-               return sampler.borderColor;
+               p = sampleTextureBorder<float>(access.getFormat(), sampler);
+
+       return isSRGB(access.getFormat()) ? sRGBToLinear(p) : p;
 }
 
 static inline bool isColorValid (const LookupPrecision& prec, const Vec4& ref, const Vec4& result)
index eafb5c1..713cc4c 100644 (file)
@@ -1235,11 +1235,33 @@ static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, i
        return isSRGB(access.getFormat()) ? sRGBToLinear(p) : p;
 }
 
-// Border texel lookup
+// Border texel lookup with color conversion.
 static inline Vec4 lookupBorder (const tcu::TextureFormat& format, const tcu::Sampler& sampler)
 {
-       DE_UNREF(format);
-       return sampler.borderColor;
+       // "lookup" for a combined format does not make sense, disallow
+       DE_ASSERT(!isCombinedDepthStencilType(format.type));
+
+       const tcu::TextureChannelClass  channelClass                    = tcu::getTextureChannelClass(format.type);
+       const bool                                              isFloat                                 = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
+       const bool                                              isFixed                                 = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
+                                                                                                                         channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
+       const bool                                              isPureInteger                   = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
+       const bool                                              isPureUnsignedInteger   = channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
+
+       if (isFloat || isFixed)
+       {
+               const Vec4 p = sampleTextureBorder<float>(format, sampler);
+               return isSRGB(format) ? sRGBToLinear(p) : p;
+       }
+       else if (isPureInteger)
+               return sampleTextureBorder<deInt32>(format, sampler).cast<float>();
+       else if (isPureUnsignedInteger)
+               return sampleTextureBorder<deUint32>(format, sampler).cast<float>();
+       else
+       {
+               DE_ASSERT(false);
+               return Vec4(-1.0);
+       }
 }
 
 static inline float execCompare (const tcu::Vec4& color, Sampler::CompareMode compare, int chanNdx, float ref_, bool isFixedPoint)
@@ -1947,9 +1969,9 @@ Vec4 gatherArray2DOffsetsCompare (const ConstPixelBufferAccess& src, const Sampl
        DE_ASSERT(src.getFormat().order == TextureFormat::D || src.getFormat().order == TextureFormat::DS);
        DE_ASSERT(sampler.compareChannel == 0);
 
-       const bool                                              isFixedPoint    = isFixedPointDepthTextureFormat(src.getFormat());
-       const Vec4                                              gathered                = fetchGatherArray2DOffsets(src, sampler, s, t, depth, 0 /* component 0: depth */, offsets);
-       Vec4                                                    result;
+       const bool      isFixedPoint    = isFixedPointDepthTextureFormat(src.getFormat());
+       const Vec4      gathered                = fetchGatherArray2DOffsets(src, sampler, s, t, depth, 0 /* component 0: depth */, offsets);
+       Vec4            result;
 
        for (int i = 0; i < 4; i++)
                result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
index 307fb2d..fde4919 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "tcuDefs.hpp"
 #include "tcuVector.hpp"
+#include "rrGenericVector.hpp"
 #include "deArrayBuffer.hpp"
 
 #include <vector>
@@ -221,8 +222,12 @@ public:
        CompareMode                     compare;
        int                                     compareChannel;
 
-       // Border color
-       Vec4                    borderColor;
+       // Border color.
+       // \note It is setter's responsibility to guarantee that the values are representable
+       //       in sampled texture's internal format.
+       // \note It is setter's responsibility to guarantee that the format is compatible with the
+       //       sampled texture's internal format. Otherwise results are undefined.
+       rr::GenericVec4         borderColor;
 
        // Seamless cube map filtering
        bool                            seamlessCubeMap;
@@ -267,7 +272,7 @@ public:
                , normalizedCoords      (true)
                , compare                       (COMPAREMODE_NONE)
                , compareChannel        (0)
-               , borderColor           (0.0f, 0.0f, 0.0f, 0.0f)
+               , borderColor           (Vec4(0.0f, 0.0f, 0.0f, 0.0f))
                , seamlessCubeMap       (false)
                , depthStencilMode      (MODE_DEPTH)
        {
index 58e2809..7edd3b8 100644 (file)
@@ -577,9 +577,9 @@ static void fillWithComponentGradients1D (const PixelBufferAccess& access, const
        DE_ASSERT(access.getHeight() == 1);
        for (int x = 0; x < access.getWidth(); x++)
        {
-               float s = ((float)x + 0.5f) / (float)access.getWidth();
+               float s = ((float)x + 0.5f) / (float)access.getWidth();
 
-               float r = linearInterpolate(s, minVal.x(), maxVal.x());
+               float r = linearInterpolate(s, minVal.x(), maxVal.x());
                float g = linearInterpolate(s, minVal.y(), maxVal.y());
                float b = linearInterpolate(s, minVal.z(), maxVal.z());
                float a = linearInterpolate(s, minVal.w(), maxVal.w());
@@ -594,10 +594,10 @@ static void fillWithComponentGradients2D (const PixelBufferAccess& access, const
        {
                for (int x = 0; x < access.getWidth(); x++)
                {
-                       float s = ((float)x + 0.5f) / (float)access.getWidth();
-                       float t = ((float)y + 0.5f) / (float)access.getHeight();
+                       float s = ((float)x + 0.5f) / (float)access.getWidth();
+                       float t = ((float)y + 0.5f) / (float)access.getHeight();
 
-                       float r = linearInterpolate((      s  +       t) *0.5f, minVal.x(), maxVal.x());
+                       float r = linearInterpolate((      s  +       t) *0.5f, minVal.x(), maxVal.x());
                        float g = linearInterpolate((      s  + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
                        float b = linearInterpolate(((1.0f-s) +       t) *0.5f, minVal.z(), maxVal.z());
                        float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
@@ -1149,4 +1149,223 @@ tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayVi
        return getEffectiveTView(src, storage, sampler);
 }
 
+//! Returns the effective swizzle of a border color. The effective swizzle is the
+//! equal to first writing an RGBA color with a write swizzle and then reading
+//! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
+static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order)
+{
+       // make sure to update these tables when channel orders are updated
+       DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 18);
+
+       static const TextureSwizzle INV         = {{ TextureSwizzle::CHANNEL_ZERO,      TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ONE     }};
+       static const TextureSwizzle R           = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ONE     }};
+       static const TextureSwizzle A           = {{ TextureSwizzle::CHANNEL_ZERO,      TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_3       }};
+       static const TextureSwizzle I           = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_0,              TextureSwizzle::CHANNEL_0,              TextureSwizzle::CHANNEL_0       }};
+       static const TextureSwizzle L           = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_0,              TextureSwizzle::CHANNEL_0,              TextureSwizzle::CHANNEL_ONE     }};
+       static const TextureSwizzle LA          = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_0,              TextureSwizzle::CHANNEL_0,              TextureSwizzle::CHANNEL_3       }};
+       static const TextureSwizzle RG          = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_1,              TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ONE     }};
+       static const TextureSwizzle RA          = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_3       }};
+       static const TextureSwizzle RGB         = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_1,              TextureSwizzle::CHANNEL_2,              TextureSwizzle::CHANNEL_ONE     }};
+       static const TextureSwizzle RGBA        = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_1,              TextureSwizzle::CHANNEL_2,              TextureSwizzle::CHANNEL_3       }};
+       static const TextureSwizzle D           = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ONE     }};
+       static const TextureSwizzle S           = {{ TextureSwizzle::CHANNEL_0,         TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ZERO,   TextureSwizzle::CHANNEL_ONE     }};
+
+       const TextureSwizzle* swizzle;
+
+       switch (order)
+       {
+               case TextureFormat::R:                  swizzle = &R;           break;
+               case TextureFormat::A:                  swizzle = &A;           break;
+               case TextureFormat::I:                  swizzle = &I;           break;
+               case TextureFormat::L:                  swizzle = &L;           break;
+               case TextureFormat::LA:                 swizzle = &LA;          break;
+               case TextureFormat::RG:                 swizzle = &RG;          break;
+               case TextureFormat::RA:                 swizzle = &RA;          break;
+               case TextureFormat::RGB:                swizzle = &RGB;         break;
+               case TextureFormat::RGBA:               swizzle = &RGBA;        break;
+               case TextureFormat::ARGB:               swizzle = &RGBA;        break;
+               case TextureFormat::BGRA:               swizzle = &RGBA;        break;
+               case TextureFormat::sR:                 swizzle = &R;           break;
+               case TextureFormat::sRG:                swizzle = &RG;          break;
+               case TextureFormat::sRGB:               swizzle = &RGB;         break;
+               case TextureFormat::sRGBA:              swizzle = &RGBA;        break;
+               case TextureFormat::D:                  swizzle = &D;           break;
+               case TextureFormat::S:                  swizzle = &S;           break;
+
+               case TextureFormat::DS:
+                       DE_ASSERT(false); // combined depth-stencil border color?
+                       swizzle = &INV;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+                       swizzle = &INV;
+                       break;
+       }
+
+#ifdef DE_DEBUG
+
+       {
+               // check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
+               const TextureSwizzle& readSwizzle       = getChannelReadSwizzle(order);
+               const TextureSwizzle& writeSwizzle      = getChannelWriteSwizzle(order);
+
+               for (int ndx = 0; ndx < 4; ++ndx)
+               {
+                       TextureSwizzle::Channel writeRead = readSwizzle.components[ndx];
+                       if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE)
+                               writeRead = writeSwizzle.components[(int)writeRead];
+                       DE_ASSERT(writeRead == swizzle->components[ndx]);
+               }
+       }
+
+#endif
+
+       return *swizzle;
+}
+
+static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
+{
+       return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0),
+                                         (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0),
+                                         (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0),
+                                         (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0));
+}
+
+static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
+{
+       return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0),
+                                         (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0),
+                                         (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0),
+                                         (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0));
+}
+
+static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits)
+{
+       return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0),
+                                         (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0),
+                                         (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0),
+                                         (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0));
+}
+
+static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler)
+{
+       const tcu::TextureChannelClass  channelClass    = getTextureChannelClass(format.type);
+       const TextureSwizzle::Channel*  channelMap              = getBorderColorReadSwizzle(format.order).components;
+       const bool                                              isFloat                 = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
+       const bool                                              isSigned                = channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
+       const float                                             valueMin                = (isSigned) ? (-1.0f) : (0.0f);
+       const float                                             valueMax                = 1.0f;
+       Vec4                                                    result;
+
+       DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
+                         channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
+                         channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
+
+       for (int c = 0; c < 4; c++)
+       {
+               const TextureSwizzle::Channel map = channelMap[c];
+               if (map == TextureSwizzle::CHANNEL_ZERO)
+                       result[c] = 0.0f;
+               else if (map == TextureSwizzle::CHANNEL_ONE)
+                       result[c] = 1.0f;
+               else if (isFloat)
+               {
+                       // floating point values are not clamped
+                       result[c] = sampler.borderColor.getAccess<float>()[(int)map];
+               }
+               else
+               {
+                       // fixed point values are clamped to a representable range
+                       result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax);
+               }
+       }
+
+       return isSRGB(format) ? sRGBToLinear(result) : result;
+}
+
+static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler)
+{
+       const tcu::TextureChannelClass  channelClass    = getTextureChannelClass(format.type);
+       const TextureSwizzle::Channel*  channelMap              = getBorderColorReadSwizzle(format.order).components;
+       const IVec4                                             channelBits             = getChannelBitDepth(format.type);
+       const IVec4                                             valueMin                = getNBitSignedIntegerVec4MinValue(channelBits);
+       const IVec4                                             valueMax                = getNBitSignedIntegerVec4MaxValue(channelBits);
+       IVec4                                                   result;
+
+       DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
+
+       for (int c = 0; c < 4; c++)
+       {
+               const TextureSwizzle::Channel map = channelMap[c];
+               if (map == TextureSwizzle::CHANNEL_ZERO)
+                       result[c] = 0;
+               else if (map == TextureSwizzle::CHANNEL_ONE)
+                       result[c] = 1;
+               else
+               {
+                       // integer values are clamped to a representable range
+                       result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]);
+               }
+       }
+
+       return result;
+}
+
+static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler)
+{
+       const tcu::TextureChannelClass  channelClass    = getTextureChannelClass(format.type);
+       const TextureSwizzle::Channel*  channelMap              = getBorderColorReadSwizzle(format.order).components;
+       const IVec4                                             channelBits             = getChannelBitDepth(format.type);
+       const UVec4                                             valueMax                = getNBitUnsignedIntegerVec4MaxValue(channelBits);
+       UVec4                                                   result;
+
+       DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
+
+       for (int c = 0; c < 4; c++)
+       {
+               const TextureSwizzle::Channel map = channelMap[c];
+               if (map == TextureSwizzle::CHANNEL_ZERO)
+                       result[c] = 0;
+               else if (map == TextureSwizzle::CHANNEL_ONE)
+                       result[c] = 1;
+               else
+               {
+                       // integer values are clamped to a representable range
+                       result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]);
+               }
+       }
+
+       return result;
+}
+
+template <typename ScalarType>
+tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler)
+{
+       const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
+
+       switch (channelClass)
+       {
+               case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+               case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+                       return getTextureBorderColorFloat(format, sampler).cast<ScalarType>();
+
+               case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+                       return getTextureBorderColorInt(format, sampler).cast<ScalarType>();
+
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+                       return getTextureBorderColorUint(format, sampler).cast<ScalarType>();
+
+               default:
+                       DE_ASSERT(false);
+                       return tcu::Vector<ScalarType, 4>();
+       }
+}
+
+// instantiation
+template tcu::Vector<float, 4>         sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
+template tcu::Vector<deInt32, 4>       sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
+template tcu::Vector<deUint32, 4>      sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
+
 } // tcu
index f1870ec..c51e303 100644 (file)
@@ -153,6 +153,9 @@ tcu::Texture2DArrayView             getEffectiveTextureView                                 (const tcu::Texture2DArrayV
 tcu::TextureCubeView           getEffectiveTextureView                                 (const tcu::TextureCubeView&            src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler);
 tcu::TextureCubeArrayView      getEffectiveTextureView                                 (const tcu::TextureCubeArrayView&       src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler);
 
+template <typename ScalarType>
+tcu::Vector<ScalarType, 4>     sampleTextureBorder                                             (const TextureFormat& format, const Sampler& sampler);
+
 } // tcu
 
 #endif // _TCUTEXTUREUTIL_HPP