Improve texture border color handling.
- 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
diff --git a/framework/common/tcuTexCompareVerifier.cpp b/framework/common/tcuTexCompareVerifier.cpp
index 9806c70..9f10295 100644
--- a/framework/common/tcuTexCompareVerifier.cpp
+++ b/framework/common/tcuTexCompareVerifier.cpp
@@ -44,11 +44,6 @@
}
#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 @@
(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 @@
{
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 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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))
diff --git a/framework/common/tcuTexLookupVerifier.cpp b/framework/common/tcuTexLookupVerifier.cpp
index 89aa55b..e7d7ccb 100644
--- a/framework/common/tcuTexLookupVerifier.cpp
+++ b/framework/common/tcuTexLookupVerifier.cpp
@@ -58,20 +58,21 @@
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)
diff --git a/framework/common/tcuTexture.cpp b/framework/common/tcuTexture.cpp
index eafb5c1..713cc4c 100644
--- a/framework/common/tcuTexture.cpp
+++ b/framework/common/tcuTexture.cpp
@@ -1235,11 +1235,33 @@
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 @@
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);
diff --git a/framework/common/tcuTexture.hpp b/framework/common/tcuTexture.hpp
index 307fb2d..fde4919 100644
--- a/framework/common/tcuTexture.hpp
+++ b/framework/common/tcuTexture.hpp
@@ -25,6 +25,7 @@
#include "tcuDefs.hpp"
#include "tcuVector.hpp"
+#include "rrGenericVector.hpp"
#include "deArrayBuffer.hpp"
#include <vector>
@@ -221,8 +222,12 @@
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 @@
, 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)
{
diff --git a/framework/common/tcuTextureUtil.cpp b/framework/common/tcuTextureUtil.cpp
index 58e2809..7edd3b8 100644
--- a/framework/common/tcuTextureUtil.cpp
+++ b/framework/common/tcuTextureUtil.cpp
@@ -577,9 +577,9 @@
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 @@
{
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 @@
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
diff --git a/framework/common/tcuTextureUtil.hpp b/framework/common/tcuTextureUtil.hpp
index f1870ec..c51e303 100644
--- a/framework/common/tcuTextureUtil.hpp
+++ b/framework/common/tcuTextureUtil.hpp
@@ -153,6 +153,9 @@
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