blob: 1b2afbdb081ff9ca14fe2b14016ab5af7a8d091d [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES 3.1 Module
* -------------------------------------------------
*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Texture border clamp tests.
*//*--------------------------------------------------------------------*/
#include "es31fTextureBorderClampTests.hpp"
#include "glsTextureTestUtil.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "tcuTexCompareVerifier.hpp"
#include "tcuCompressedTexture.hpp"
#include "tcuResultCollector.hpp"
#include "tcuSurface.hpp"
#include "tcuSeedBuilder.hpp"
#include "tcuVectorUtil.hpp"
#include "rrGenericVector.hpp"
#include "gluContextInfo.hpp"
#include "gluTexture.hpp"
#include "gluTextureUtil.hpp"
#include "gluPixelTransfer.hpp"
#include "gluStrUtil.hpp"
#include "gluObjectWrapper.hpp"
#include "gluShaderProgram.hpp"
#include "gluDrawUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include "deRandom.hpp"
#include <limits>
namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{
enum SizeType
{
SIZE_POT = 0,
SIZE_NPOT
};
bool filterRequiresFilterability (deUint32 filter)
{
switch (filter)
{
case GL_NEAREST:
case GL_NEAREST_MIPMAP_NEAREST:
return false;
case GL_LINEAR:
case GL_LINEAR_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
case GL_LINEAR_MIPMAP_LINEAR:
return true;
default:
DE_ASSERT(false);
return false;
}
}
bool isDepthFormat (deUint32 format, tcu::Sampler::DepthStencilMode mode)
{
if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA || format == GL_ALPHA || format == GL_BGRA)
{
// Unsized formats are a special case
return false;
}
else if (glu::isCompressedFormat(format))
{
// no known compressed depth formats
return false;
}
else
{
const tcu::TextureFormat fmt = glu::mapGLInternalFormat(format);
if (fmt.order == tcu::TextureFormat::D)
{
DE_ASSERT(mode == tcu::Sampler::MODE_DEPTH);
return true;
}
else if (fmt.order == tcu::TextureFormat::DS && mode == tcu::Sampler::MODE_DEPTH)
return true;
else
return false;
}
}
bool isStencilFormat (deUint32 format, tcu::Sampler::DepthStencilMode mode)
{
if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA || format == GL_ALPHA || format == GL_BGRA)
{
// Unsized formats are a special case
return false;
}
else if (glu::isCompressedFormat(format))
{
// no known compressed stencil formats
return false;
}
else
{
const tcu::TextureFormat fmt = glu::mapGLInternalFormat(format);
if (fmt.order == tcu::TextureFormat::S)
{
DE_ASSERT(mode == tcu::Sampler::MODE_STENCIL);
return true;
}
else if (fmt.order == tcu::TextureFormat::DS && mode == tcu::Sampler::MODE_STENCIL)
return true;
else
return false;
}
}
tcu::TextureChannelClass getFormatChannelClass (deUint32 format, tcu::Sampler::DepthStencilMode mode)
{
if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA || format == GL_ALPHA || format == GL_BGRA)
{
// Unsized formats are a special c, use UNORM8
return tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
}
else if (glu::isCompressedFormat(format))
{
const tcu::CompressedTexFormat compressedFmt = glu::mapGLCompressedTexFormat(format);
const tcu::TextureFormat uncompressedFmt = tcu::getUncompressedFormat(compressedFmt);
return tcu::getTextureChannelClass(uncompressedFmt.type);
}
else
{
const tcu::TextureFormat fmt = glu::mapGLInternalFormat(format);
const tcu::TextureFormat effectiveFmt = tcu::getEffectiveDepthStencilTextureFormat(fmt, mode);
return tcu::getTextureChannelClass(effectiveFmt.type);
}
}
int getDimensionNumBlocks (int dimensionSize, int blockSize)
{
// ceil( a / b )
return (dimensionSize + blockSize - 1) / blockSize;
}
void generateDefaultCompressedData (tcu::CompressedTexture& dst, const tcu::CompressedTexFormat& format)
{
const int blockByteSize = tcu::getBlockSize(format);
const tcu::IVec3 blockPixelSize = tcu::getBlockPixelSize(format);
const tcu::IVec3 numBlocks (getDimensionNumBlocks(dst.getWidth(), blockPixelSize.x()),
getDimensionNumBlocks(dst.getHeight(), blockPixelSize.y()),
getDimensionNumBlocks(dst.getDepth(), blockPixelSize.z()));
const int numTotalBlocks = numBlocks.x() * numBlocks.y() * numBlocks.z();
const int dataSize = numTotalBlocks * blockByteSize;
DE_ASSERT(dst.getDataSize() == dataSize);
if (tcu::isAstcFormat(format))
{
// generate data that is valid in LDR mode
const int BLOCK_SIZE = 16;
const deUint8 block[BLOCK_SIZE] = { 252, 253, 255, 255, 255, 255, 255, 255, 223, 251, 28, 206, 54, 251, 160, 174 };
DE_ASSERT(blockByteSize == BLOCK_SIZE);
for (int ndx = 0; ndx < numTotalBlocks; ++ndx)
deMemcpy((deUint8*)dst.getData() + ndx * BLOCK_SIZE, block, BLOCK_SIZE);
}
else
{
// any data is ok
de::Random rnd(0xabc);
for (int ndx = 0; ndx < dataSize; ++ndx)
((deUint8*)dst.getData())[ndx] = rnd.getUint8();
}
}
template <typename T>
struct TextureTraits
{
};
template <>
struct TextureTraits<glu::Texture2D>
{
typedef tcu::IVec2 SizeType;
static de::MovePtr<glu::Texture2D> createTextureFromInternalFormat (glu::RenderContext& renderCtx, deUint32 texFormat, const tcu::IVec2& size)
{
return de::MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, texFormat, size.x(), size.y()));
}
static de::MovePtr<glu::Texture2D> createTextureFromFormatAndType (glu::RenderContext& renderCtx, deUint32 texFormat, deUint32 type, const tcu::IVec2& size)
{
return de::MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, texFormat, type, size.x(), size.y()));
}
static de::MovePtr<glu::Texture2D> createTextureFromCompressedData (glu::RenderContext& renderCtx,
const glu::ContextInfo& ctxInfo,
const tcu::CompressedTexture& compressedLevel,
const tcu::TexDecompressionParams& decompressionParams)
{
return de::MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx,
ctxInfo,
1,
&compressedLevel,
decompressionParams));
}
static int getTextureNumLayers (const tcu::IVec2& size)
{
// 2D textures have one layer
DE_UNREF(size);
return 1;
}
};
template <>
struct TextureTraits<glu::Texture3D>
{
typedef tcu::IVec3 SizeType;
static de::MovePtr<glu::Texture3D> createTextureFromInternalFormat (glu::RenderContext& renderCtx, deUint32 texFormat, const tcu::IVec3& size)
{
return de::MovePtr<glu::Texture3D>(new glu::Texture3D(renderCtx, texFormat, size.x(), size.y(), size.z()));
}
static de::MovePtr<glu::Texture3D> createTextureFromFormatAndType (glu::RenderContext& renderCtx, deUint32 texFormat, deUint32 type, const tcu::IVec3& size)
{
return de::MovePtr<glu::Texture3D>(new glu::Texture3D(renderCtx, texFormat, type, size.x(), size.y(), size.z()));
}
static de::MovePtr<glu::Texture3D> createTextureFromCompressedData (glu::RenderContext& renderCtx,
const glu::ContextInfo& ctxInfo,
const tcu::CompressedTexture& compressedLevel,
const tcu::TexDecompressionParams& decompressionParams)
{
return de::MovePtr<glu::Texture3D>(new glu::Texture3D(renderCtx,
ctxInfo,
1,
&compressedLevel,
decompressionParams));
}
static int getTextureNumLayers (const tcu::IVec3& size)
{
// 3D textures have Z layers
return size.z();
}
};
template <typename T>
de::MovePtr<T> genDefaultTexture (glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, deUint32 texFormat, const typename TextureTraits<T>::SizeType& size)
{
de::MovePtr<T> texture;
if (isDepthFormat(texFormat, tcu::Sampler::MODE_DEPTH) || isStencilFormat(texFormat, tcu::Sampler::MODE_STENCIL))
{
// fill different channels with different gradients
texture = TextureTraits<T>::createTextureFromInternalFormat(renderCtx, texFormat, size);
texture->getRefTexture().allocLevel(0);
if (isDepthFormat(texFormat, tcu::Sampler::MODE_DEPTH))
{
// fill depth with 0 -> 1
const tcu::PixelBufferAccess depthAccess = tcu::getEffectiveDepthStencilAccess(texture->getRefTexture().getLevel(0), tcu::Sampler::MODE_DEPTH);
tcu::fillWithComponentGradients(depthAccess, tcu::Vec4(0.0f), tcu::Vec4(1.0f));
}
if (isStencilFormat(texFormat, tcu::Sampler::MODE_STENCIL))
{
// fill stencil with 0 -> max
const tcu::PixelBufferAccess stencilAccess = tcu::getEffectiveDepthStencilAccess(texture->getRefTexture().getLevel(0), tcu::Sampler::MODE_STENCIL);
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(stencilAccess.getFormat());
// Flip y to make stencil and depth cases not look identical
tcu::fillWithComponentGradients(tcu::flipYAccess(stencilAccess), texFormatInfo.valueMax, texFormatInfo.valueMin);
}
texture->upload();
}
else if (!glu::isCompressedFormat(texFormat))
{
if (texFormat == GL_LUMINANCE || texFormat == GL_LUMINANCE_ALPHA || texFormat == GL_ALPHA || texFormat == GL_BGRA)
texture = TextureTraits<T>::createTextureFromFormatAndType(renderCtx, texFormat, GL_UNSIGNED_BYTE, size);
else
texture = TextureTraits<T>::createTextureFromInternalFormat(renderCtx, texFormat, size);
// Fill level 0.
texture->getRefTexture().allocLevel(0);
// fill with gradient min -> max
{
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(texture->getRefTexture().getFormat());
const tcu::Vec4 rampLow = texFormatInfo.valueMin;
const tcu::Vec4 rampHigh = texFormatInfo.valueMax;
tcu::fillWithComponentGradients(texture->getRefTexture().getLevel(0), rampLow, rampHigh);
}
texture->upload();
}
else
{
const tcu::CompressedTexFormat compressedFormat = glu::mapGLCompressedTexFormat(texFormat);
const int numLayers = TextureTraits<T>::getTextureNumLayers(size);
tcu::CompressedTexture compressedLevel (compressedFormat, size.x(), size.y(), numLayers);
const bool isAstcFormat = tcu::isAstcFormat(compressedFormat);
tcu::TexDecompressionParams decompressionParams ((isAstcFormat) ? (tcu::TexDecompressionParams::ASTCMODE_LDR) : (tcu::TexDecompressionParams::ASTCMODE_LAST));
generateDefaultCompressedData(compressedLevel, compressedFormat);
texture = TextureTraits<T>::createTextureFromCompressedData(renderCtx,
ctxInfo,
compressedLevel,
decompressionParams);
}
return texture;
}
int getNBitIntegerMaxValue (bool isSigned, int numBits)
{
DE_ASSERT(numBits < 32);
if (numBits == 0)
return 0;
else if (isSigned)
return deIntMaxValue32(numBits);
else
return deUintMaxValue32(numBits);
}
int getNBitIntegerMinValue (bool isSigned, int numBits)
{
DE_ASSERT(numBits < 32);
if (numBits == 0)
return 0;
else if (isSigned)
return deIntMinValue32(numBits);
else
return 0;
}
tcu::IVec4 getNBitIntegerVec4MaxValue (bool isSigned, const tcu::IVec4& numBits)
{
return tcu::IVec4(getNBitIntegerMaxValue(isSigned, numBits[0]),
getNBitIntegerMaxValue(isSigned, numBits[1]),
getNBitIntegerMaxValue(isSigned, numBits[2]),
getNBitIntegerMaxValue(isSigned, numBits[3]));
}
tcu::IVec4 getNBitIntegerVec4MinValue (bool isSigned, const tcu::IVec4& numBits)
{
return tcu::IVec4(getNBitIntegerMinValue(isSigned, numBits[0]),
getNBitIntegerMinValue(isSigned, numBits[1]),
getNBitIntegerMinValue(isSigned, numBits[2]),
getNBitIntegerMinValue(isSigned, numBits[3]));
}
rr::GenericVec4 mapToFormatColorUnits (const tcu::TextureFormat& texFormat, const tcu::Vec4& normalizedRange)
{
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(texFormat);
switch (tcu::getTextureChannelClass(texFormat.type))
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: return rr::GenericVec4(normalizedRange);
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: return rr::GenericVec4(normalizedRange * 2.0f - 1.0f);
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: return rr::GenericVec4(texFormatInfo.valueMin + normalizedRange * texFormatInfo.valueMax);
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: return rr::GenericVec4(tcu::mix(texFormatInfo.valueMin, texFormatInfo.valueMax, normalizedRange).cast<deInt32>());
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: return rr::GenericVec4(tcu::mix(texFormatInfo.valueMin, texFormatInfo.valueMax, normalizedRange).cast<deUint32>());
default:
DE_ASSERT(false);
return rr::GenericVec4();
}
}
rr::GenericVec4 mapToFormatColorRepresentable (const tcu::TextureFormat& texFormat, const tcu::Vec4& normalizedRange)
{
// make sure value is representable in the target format and clear channels
// not present in the target format.
const rr::GenericVec4 inFormatUnits = mapToFormatColorUnits(texFormat, normalizedRange);
const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(texFormat);
de::ArrayBuffer<deUint8, 4> buffer (texFormat.getPixelSize());
tcu::PixelBufferAccess access (texFormat, tcu::IVec3(1, 1, 1), buffer.getPtr());
if (tcu::isSRGB(texFormat))
{
DE_ASSERT(texFormat.type == tcu::TextureFormat::UNORM_INT8);
// make sure border color (in linear space) can be converted to 8-bit sRGB space without
// significant loss.
const tcu::Vec4 sRGB = tcu::linearToSRGB(normalizedRange);
const tcu::IVec4 sRGB8 = tcu::IVec4(tcu::floatToU8(sRGB[0]),
tcu::floatToU8(sRGB[1]),
tcu::floatToU8(sRGB[2]),
tcu::floatToU8(sRGB[3]));
const tcu::Vec4 linearized = tcu::sRGBToLinear(tcu::Vec4((float)sRGB8[0] / 255.0f,
(float)sRGB8[1] / 255.0f,
(float)sRGB8[2] / 255.0f,
(float)sRGB8[3] / 255.0f));
return rr::GenericVec4(tcu::select(linearized, tcu::Vec4(0.0f), channelMask));
}
switch (tcu::getTextureChannelClass(texFormat.type))
{
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
access.setPixel(inFormatUnits.get<float>(), 0, 0);
return rr::GenericVec4(tcu::select(access.getPixel(0, 0), tcu::Vec4(0.0f), channelMask));
}
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
{
access.setPixel(inFormatUnits.get<deInt32>(), 0, 0);
return rr::GenericVec4(tcu::select(access.getPixelInt(0, 0), tcu::IVec4(0), channelMask));
}
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
{
access.setPixel(inFormatUnits.get<deUint32>(), 0, 0);
return rr::GenericVec4(tcu::select(access.getPixelUint(0, 0), tcu::UVec4(0u), channelMask));
}
default:
{
DE_ASSERT(false);
return rr::GenericVec4();
}
}
}
bool isCoreFilterableFormat (deUint32 format, tcu::Sampler::DepthStencilMode mode)
{
const bool isLuminanceOrAlpha = (format == GL_LUMINANCE || format == GL_ALPHA || format == GL_LUMINANCE_ALPHA); // special case for luminance/alpha
const bool isUnsizedColorFormat = (format == GL_BGRA);
const bool isCompressed = glu::isCompressedFormat(format);
const bool isDepth = isDepthFormat(format, mode);
const bool isStencil = isStencilFormat(format, mode);
// special cases
if (isLuminanceOrAlpha || isUnsizedColorFormat || isCompressed)
return true;
if (isStencil || isDepth)
return false;
// color case
return glu::isGLInternalColorFormatFilterable(format);
}
class TextureBorderClampTest : public TestCase
{
public:
enum StateType
{
STATE_SAMPLER_PARAM = 0,
STATE_TEXTURE_PARAM,
STATE_LAST
};
enum SamplingFunction
{
SAMPLE_FILTER = 0,
SAMPLE_GATHER,
SAMPLE_LAST
};
enum Flag
{
FLAG_USE_SHADOW_SAMPLER = (1u << 0),
};
struct IterationConfig
{
tcu::Vec2 p0;
tcu::Vec2 p1;
rr::GenericVec4 borderColor;
tcu::Vec4 lookupScale;
tcu::Vec4 lookupBias;
deUint32 minFilter;
deUint32 magFilter;
std::string description;
deUint32 sWrapMode;
deUint32 tWrapMode;
deUint32 compareMode;
float compareRef;
};
TextureBorderClampTest (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
StateType stateType,
int texWidth,
int texHeight,
SamplingFunction samplingFunction,
deUint32 flags = 0);
~TextureBorderClampTest (void);
protected:
void init (void);
void deinit (void);
private:
IterateResult iterate (void);
void logParams (const IterationConfig& config,
const glu::TextureTestUtil::ReferenceParams& samplerParams);
void renderTo (tcu::Surface& surface,
const IterationConfig& config,
const glu::TextureTestUtil::ReferenceParams& samplerParams);
void renderQuad (const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams);
void verifyImage (const tcu::Surface& image,
const IterationConfig& config,
const glu::TextureTestUtil::ReferenceParams& samplerParams);
bool verifyTextureSampleResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::LodPrecision& lodPrecision,
const tcu::LookupPrecision& lookupPrecision);
bool verifyTextureCompareResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::TexComparePrecision& texComparePrecision,
const tcu::TexComparePrecision& lowQualityTexComparePrecision,
const tcu::LodPrecision& lodPrecision,
const tcu::LodPrecision& lowQualityLodPrecision);
bool verifyTextureGatherResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::LookupPrecision& lookupPrecision);
bool verifyTextureGatherCmpResult(const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::TexComparePrecision& texComparePrecision,
const tcu::TexComparePrecision& lowQualityTexComparePrecision);
deUint32 getIterationSeed (const IterationConfig& config) const;
glu::TextureTestUtil::ReferenceParams genSamplerParams (const IterationConfig& config) const;
glu::ShaderProgram* genGatherProgram (void) const;
virtual int getNumIterations (void) const = 0;
virtual IterationConfig getIteration (int ndx) const = 0;
protected:
const glu::Texture2D* getTexture (void) const;
const deUint32 m_texFormat;
const tcu::Sampler::DepthStencilMode m_sampleMode;
const tcu::TextureChannelClass m_channelClass;
const StateType m_stateType;
const int m_texHeight;
const int m_texWidth;
const SamplingFunction m_samplingFunction;
const bool m_useShadowSampler;
private:
enum
{
VIEWPORT_WIDTH = 128,
VIEWPORT_HEIGHT = 128,
};
de::MovePtr<glu::Texture2D> m_texture;
de::MovePtr<gls::TextureTestUtil::TextureRenderer> m_renderer;
de::MovePtr<glu::ShaderProgram> m_gatherProgram;
int m_iterationNdx;
tcu::ResultCollector m_result;
};
TextureBorderClampTest::TextureBorderClampTest (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
StateType stateType,
int texWidth,
int texHeight,
SamplingFunction samplingFunction,
deUint32 flags)
: TestCase (context, name, description)
, m_texFormat (texFormat)
, m_sampleMode (mode)
, m_channelClass (getFormatChannelClass(texFormat, mode))
, m_stateType (stateType)
, m_texHeight (texHeight)
, m_texWidth (texWidth)
, m_samplingFunction (samplingFunction)
, m_useShadowSampler ((flags & FLAG_USE_SHADOW_SAMPLER) != 0)
, m_iterationNdx (0)
, m_result (context.getTestContext().getLog())
{
DE_ASSERT(stateType < STATE_LAST);
DE_ASSERT(samplingFunction < SAMPLE_LAST);
// mode must be set for combined depth-stencil formats
DE_ASSERT(m_channelClass != tcu::TEXTURECHANNELCLASS_LAST || mode != tcu::Sampler::MODE_LAST);
}
TextureBorderClampTest::~TextureBorderClampTest (void)
{
deinit();
}
void TextureBorderClampTest::init (void)
{
// requirements
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_border_clamp"))
throw tcu::NotSupportedError("Test requires GL_EXT_texture_border_clamp extension");
if (glu::isCompressedFormat(m_texFormat) &&
!supportsES32 &&
tcu::isAstcFormat(glu::mapGLCompressedTexFormat(m_texFormat)) &&
!m_context.getContextInfo().isExtensionSupported("GL_KHR_texture_compression_astc_ldr"))
{
throw tcu::NotSupportedError("Test requires GL_KHR_texture_compression_astc_ldr extension");
}
if (m_texFormat == GL_BGRA && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_format_BGRA8888"))
throw tcu::NotSupportedError("Test requires GL_EXT_texture_format_BGRA8888 extension");
if (m_context.getRenderTarget().getWidth() < VIEWPORT_WIDTH ||
m_context.getRenderTarget().getHeight() < VIEWPORT_HEIGHT)
{
throw tcu::NotSupportedError("Test requires " + de::toString<int>(VIEWPORT_WIDTH) + "x" + de::toString<int>(VIEWPORT_HEIGHT) + " viewport");
}
// resources
m_texture = genDefaultTexture<glu::Texture2D>(m_context.getRenderContext(), m_context.getContextInfo(), m_texFormat, tcu::IVec2(m_texWidth, m_texHeight));
m_testCtx.getLog() << tcu::TestLog::Message
<< "Created texture with format " << glu::getTextureFormatName(m_texFormat)
<< ", size (" << m_texture->getRefTexture().getWidth() << ", " << m_texture->getRefTexture().getHeight() << ")\n"
<< "Setting sampling state using " << ((m_stateType == STATE_TEXTURE_PARAM) ? ("texture state") : ("sampler state"))
<< tcu::TestLog::EndMessage;
if (m_samplingFunction == SAMPLE_FILTER)
{
const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
m_renderer = de::MovePtr<gls::TextureTestUtil::TextureRenderer>(new gls::TextureTestUtil::TextureRenderer(m_context.getRenderContext(), m_testCtx.getLog(), glslVersion, glu::PRECISION_HIGHP));
}
else
{
m_gatherProgram = de::MovePtr<glu::ShaderProgram>(genGatherProgram());
m_testCtx.getLog() << tcu::TestLog::Message
<< "Using texture gather to sample texture"
<< tcu::TestLog::EndMessage
<< *m_gatherProgram;
if (!m_gatherProgram->isOk())
throw tcu::TestError("failed to build program");
}
}
void TextureBorderClampTest::deinit (void)
{
m_texture.clear();
m_renderer.clear();
m_gatherProgram.clear();
}
TextureBorderClampTest::IterateResult TextureBorderClampTest::iterate (void)
{
const IterationConfig iterationConfig = getIteration(m_iterationNdx);
const std::string iterationDesc = "Iteration " + de::toString(m_iterationNdx+1) + (iterationConfig.description.empty() ? ("") : (" - " + iterationConfig.description));
const tcu::ScopedLogSection section (m_testCtx.getLog(), "Iteration", iterationDesc);
tcu::Surface renderedFrame (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
const glu::TextureTestUtil::ReferenceParams samplerParams = genSamplerParams(iterationConfig);
logParams(iterationConfig, samplerParams);
renderTo(renderedFrame, iterationConfig, samplerParams);
verifyImage(renderedFrame, iterationConfig, samplerParams);
if (++m_iterationNdx == getNumIterations())
{
m_result.setTestContextResult(m_testCtx);
return STOP;
}
return CONTINUE;
}
void TextureBorderClampTest::logParams (const IterationConfig& config, const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
const std::string borderColorString = (m_channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) ? (de::toString(config.borderColor.get<deInt32>()))
: (m_channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) ? (de::toString(config.borderColor.get<deUint32>()))
: (de::toString(config.borderColor.get<float>()));
m_testCtx.getLog() << tcu::TestLog::Message
<< "Rendering full screen quad, tex coords bottom-left: " << config.p0 << ", top-right " << config.p1 << "\n"
<< "Border color is " << borderColorString << "\n"
<< "Texture lookup bias: " << samplerParams.colorBias << "\n"
<< "Texture lookup scale: " << samplerParams.colorScale << "\n"
<< "Filters: min = " << glu::getTextureFilterName(glu::getGLFilterMode(samplerParams.sampler.minFilter))
<< ", mag = " << glu::getTextureFilterName(glu::getGLFilterMode(samplerParams.sampler.magFilter)) << "\n"
<< "Wrap mode: s = " << glu::getRepeatModeStr(config.sWrapMode)
<< ", t = " << glu::getRepeatModeStr(config.tWrapMode) << "\n"
<< tcu::TestLog::EndMessage;
if (m_sampleMode == tcu::Sampler::MODE_DEPTH)
m_testCtx.getLog() << tcu::TestLog::Message << "Depth stencil texture mode is DEPTH_COMPONENT" << tcu::TestLog::EndMessage;
else if (m_sampleMode == tcu::Sampler::MODE_STENCIL)
m_testCtx.getLog() << tcu::TestLog::Message << "Depth stencil texture mode is STENCIL_INDEX" << tcu::TestLog::EndMessage;
if (config.compareMode != GL_NONE)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Texture mode is COMPARE_REF_TO_TEXTURE, mode = " << glu::getCompareFuncStr(config.compareMode) << "\n"
<< "Compare reference value = " << config.compareRef << "\n"
<< tcu::TestLog::EndMessage;
}
}
void TextureBorderClampTest::renderTo (tcu::Surface& surface,
const IterationConfig& config,
const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const gls::TextureTestUtil::RandomViewport viewport (m_context.getRenderTarget(), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, getIterationSeed(config));
std::vector<float> texCoord;
de::MovePtr<glu::Sampler> sampler;
glu::TextureTestUtil::computeQuadTexCoord2D(texCoord, config.p0, config.p1);
// Bind to unit 0.
gl.activeTexture(GL_TEXTURE0);
gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
if (m_sampleMode == tcu::Sampler::MODE_DEPTH)
gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
else if (m_sampleMode == tcu::Sampler::MODE_STENCIL)
gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
if (config.compareMode == GL_NONE)
{
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_ALWAYS);
}
else
{
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, config.compareMode);
}
if (m_stateType == STATE_TEXTURE_PARAM)
{
// Setup filtering and wrap modes.
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(samplerParams.sampler.wrapS));
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(samplerParams.sampler.wrapT));
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(samplerParams.sampler.minFilter));
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(samplerParams.sampler.magFilter));
switch (m_channelClass)
{
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
gl.texParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, config.borderColor.getAccess<float>());
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
gl.texParameterIiv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, config.borderColor.getAccess<deInt32>());
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
gl.texParameterIuiv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, config.borderColor.getAccess<deUint32>());
break;
default:
DE_ASSERT(false);
}
}
else if (m_stateType == STATE_SAMPLER_PARAM)
{
const tcu::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
// Setup filtering and wrap modes to bad values
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.texParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, blue.getPtr()); // just set some unlikely color
// setup sampler to correct values
sampler = de::MovePtr<glu::Sampler>(new glu::Sampler(m_context.getRenderContext()));
gl.samplerParameteri(**sampler, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(samplerParams.sampler.wrapS));
gl.samplerParameteri(**sampler, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(samplerParams.sampler.wrapT));
gl.samplerParameteri(**sampler, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(samplerParams.sampler.minFilter));
gl.samplerParameteri(**sampler, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(samplerParams.sampler.magFilter));
switch (m_channelClass)
{
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
gl.samplerParameterfv(**sampler, GL_TEXTURE_BORDER_COLOR, config.borderColor.getAccess<float>());
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
gl.samplerParameterIiv(**sampler, GL_TEXTURE_BORDER_COLOR, config.borderColor.getAccess<deInt32>());
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
gl.samplerParameterIuiv(**sampler, GL_TEXTURE_BORDER_COLOR, config.borderColor.getAccess<deUint32>());
break;
default:
DE_ASSERT(false);
}
gl.bindSampler(0, **sampler);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
renderQuad(&texCoord[0], samplerParams);
glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, surface.getAccess());
}
void TextureBorderClampTest::renderQuad (const float* texCoord, const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
// use TextureRenderer for basic rendering, use custom for gather
if (m_samplingFunction == SAMPLE_FILTER)
m_renderer->renderQuad(0, texCoord, samplerParams);
else
{
static const float position[] =
{
-1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, +1.0f, 0.0f, 1.0f,
+1.0f, -1.0f, 0.0f, 1.0f,
+1.0f, +1.0f, 0.0f, 1.0f
};
static const deUint16 indices[] =
{
0, 1, 2, 2, 1, 3
};
const glu::VertexArrayBinding vertexArrays[] =
{
glu::va::Float("a_position", 4, 4, 0, &position[0]),
glu::va::Float("a_texcoord", 2, 4, 0, texCoord)
};
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const deUint32 progId = m_gatherProgram->getProgram();
gl.useProgram(progId);
gl.uniform1i(gl.getUniformLocation(progId, "u_sampler"), 0);
if (m_useShadowSampler)
gl.uniform1f(gl.getUniformLocation(progId, "u_ref"), samplerParams.ref);
gl.uniform4fv(gl.getUniformLocation(progId, "u_colorScale"), 1, samplerParams.colorScale.getPtr());
gl.uniform4fv(gl.getUniformLocation(progId, "u_colorBias"), 1, samplerParams.colorBias.getPtr());
glu::draw(m_context.getRenderContext(), progId, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
}
}
void TextureBorderClampTest::verifyImage (const tcu::Surface& renderedFrame,
const IterationConfig& config,
const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
tcu::LodPrecision lodPrecision;
std::vector<float> texCoord;
bool verificationOk;
glu::TextureTestUtil::computeQuadTexCoord2D(texCoord, config.p0, config.p1);
lodPrecision.derivateBits = 18;
lodPrecision.lodBits = 5;
if (samplerParams.sampler.compare == tcu::Sampler::COMPAREMODE_NONE)
{
const tcu::TextureFormat texFormat = tcu::getEffectiveDepthStencilTextureFormat(m_texture->getRefTexture().getFormat(), m_sampleMode);
const bool isNearestMinFilter = samplerParams.sampler.minFilter == tcu::Sampler::NEAREST || samplerParams.sampler.minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST;
const bool isNearestMagFilter = samplerParams.sampler.magFilter == tcu::Sampler::NEAREST;
const bool isNearestOnly = isNearestMinFilter && isNearestMagFilter;
const bool isSRGB = texFormat.order == tcu::TextureFormat::sRGB || texFormat.order == tcu::TextureFormat::sRGBA;
const int colorErrorBits = (isNearestOnly && !isSRGB) ? (1) : (2);
const tcu::IVec4 colorBits = tcu::max(glu::TextureTestUtil::getBitsVec(pixelFormat) - tcu::IVec4(colorErrorBits), tcu::IVec4(0));
tcu::LookupPrecision lookupPrecision;
lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / samplerParams.colorScale;
lookupPrecision.coordBits = tcu::IVec3(20,20,0);
lookupPrecision.uvwBits = tcu::IVec3(5,5,0);
lookupPrecision.colorMask = glu::TextureTestUtil::getCompareMask(pixelFormat);
if (m_samplingFunction == SAMPLE_FILTER)
{
verificationOk = verifyTextureSampleResult(renderedFrame.getAccess(),
&texCoord[0],
samplerParams,
lodPrecision,
lookupPrecision);
}
else if (m_samplingFunction == SAMPLE_GATHER)
{
verificationOk = verifyTextureGatherResult(renderedFrame.getAccess(),
&texCoord[0],
samplerParams,
lookupPrecision);
}
else
{
DE_ASSERT(false);
verificationOk = false;
}
}
else
{
tcu::TexComparePrecision texComparePrecision;
tcu::TexComparePrecision lowQualityTexComparePrecision;
tcu::LodPrecision lowQualityLodPrecision = lodPrecision;
texComparePrecision.coordBits = tcu::IVec3(20,20,0);
texComparePrecision.uvwBits = tcu::IVec3(7,7,0);
texComparePrecision.pcfBits = 5;
texComparePrecision.referenceBits = 16;
texComparePrecision.resultBits = de::max(0, pixelFormat.redBits - 1);
lowQualityTexComparePrecision.coordBits = tcu::IVec3(20,20,0);
lowQualityTexComparePrecision.uvwBits = tcu::IVec3(4,4,0);
lowQualityTexComparePrecision.pcfBits = 0;
lowQualityTexComparePrecision.referenceBits = 16;
lowQualityTexComparePrecision.resultBits = de::max(0, pixelFormat.redBits - 1);
lowQualityLodPrecision.lodBits = 4;
if (m_samplingFunction == SAMPLE_FILTER)
{
verificationOk = verifyTextureCompareResult(renderedFrame.getAccess(),
&texCoord[0],
samplerParams,
texComparePrecision,
lowQualityTexComparePrecision,
lodPrecision,
lowQualityLodPrecision);
}
else if (m_samplingFunction == SAMPLE_GATHER)
{
verificationOk = verifyTextureGatherCmpResult(renderedFrame.getAccess(),
&texCoord[0],
samplerParams,
texComparePrecision,
lowQualityTexComparePrecision);
}
else
{
DE_ASSERT(false);
verificationOk = false;
}
}
if (!verificationOk)
m_result.fail("Image verification failed");
}
bool TextureBorderClampTest::verifyTextureSampleResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::LodPrecision& lodPrecision,
const tcu::LookupPrecision& lookupPrecision)
{
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
tcu::Surface reference (renderedFrame.getWidth(), renderedFrame.getHeight());
tcu::Surface errorMask (renderedFrame.getWidth(), renderedFrame.getHeight());
int numFailedPixels;
glu::TextureTestUtil::sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), m_texture->getRefTexture(), texCoord, samplerParams);
numFailedPixels = glu::TextureTestUtil::computeTextureLookupDiff(renderedFrame, reference.getAccess(), errorMask.getAccess(), m_texture->getRefTexture(),
texCoord, samplerParams, lookupPrecision, lodPrecision, m_testCtx.getWatchDog());
if (numFailedPixels > 0)
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
<< tcu::TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_testCtx.getLog() << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
return (numFailedPixels == 0);
}
bool TextureBorderClampTest::verifyTextureCompareResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoord,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::TexComparePrecision& texComparePrecision,
const tcu::TexComparePrecision& lowQualityTexComparePrecision,
const tcu::LodPrecision& lodPrecision,
const tcu::LodPrecision& lowQualityLodPrecision)
{
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
const int colorErrorBits = 1;
const tcu::IVec4 nonShadowBits = tcu::max(glu::TextureTestUtil::getBitsVec(pixelFormat) - tcu::IVec4(colorErrorBits), tcu::IVec4(0));
const tcu::Vec3 nonShadowThreshold = tcu::computeFixedPointThreshold(nonShadowBits).swizzle(1,2,3);
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
const tcu::Texture2DView effectiveView = tcu::getEffectiveTextureView(m_texture->getRefTexture(), srcLevelStorage, samplerParams.sampler);
tcu::Surface reference (renderedFrame.getWidth(), renderedFrame.getHeight());
tcu::Surface errorMask (renderedFrame.getWidth(), renderedFrame.getHeight());
int numFailedPixels;
glu::TextureTestUtil::sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), effectiveView, texCoord, samplerParams);
numFailedPixels = glu::TextureTestUtil::computeTextureCompareDiff(renderedFrame, reference.getAccess(), errorMask.getAccess(), effectiveView,
texCoord, samplerParams, texComparePrecision, lodPrecision, nonShadowThreshold);
if (numFailedPixels > 0)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Warning: Verification assuming high-quality PCF filtering failed."
<< tcu::TestLog::EndMessage;
numFailedPixels = glu::TextureTestUtil::computeTextureCompareDiff(renderedFrame, reference.getAccess(), errorMask.getAccess(), effectiveView,
texCoord, samplerParams, lowQualityTexComparePrecision, lowQualityLodPrecision, nonShadowThreshold);
if (numFailedPixels > 0)
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << tcu::TestLog::EndMessage;
else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
}
if (numFailedPixels > 0)
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
<< tcu::TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_testCtx.getLog() << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
return (numFailedPixels == 0);
}
template <typename T>
static inline T triQuadInterpolate (const T (&values)[4], float xFactor, float yFactor)
{
if (xFactor + yFactor < 1.0f)
return values[0] + (values[2]-values[0])*xFactor + (values[1]-values[0])*yFactor;
else
return values[3] + (values[1]-values[3])*(1.0f-xFactor) + (values[2]-values[3])*(1.0f-yFactor);
}
bool TextureBorderClampTest::verifyTextureGatherResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoordArray,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::LookupPrecision& lookupPrecision)
{
const tcu::Vec2 texCoords[4] =
{
tcu::Vec2(texCoordArray[0], texCoordArray[1]),
tcu::Vec2(texCoordArray[2], texCoordArray[3]),
tcu::Vec2(texCoordArray[4], texCoordArray[5]),
tcu::Vec2(texCoordArray[6], texCoordArray[7]),
};
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
const deUint8 fbColormask = tcu::getColorMask(pixelFormat);
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
const tcu::Texture2DView effectiveView = tcu::getEffectiveTextureView(m_texture->getRefTexture(), srcLevelStorage, samplerParams.sampler);
tcu::Surface reference (renderedFrame.getWidth(), renderedFrame.getHeight());
tcu::Surface errorMask (renderedFrame.getWidth(), renderedFrame.getHeight());
int numFailedPixels = 0;
tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
for (int py = 0; py < reference.getHeight(); ++py)
for (int px = 0; px < reference.getWidth(); ++px)
{
const tcu::Vec2 viewportCoord = (tcu::Vec2((float)px, (float)py) + tcu::Vec2(0.5f)) / tcu::Vec2((float)reference.getWidth(), (float)reference.getHeight());
const tcu::Vec2 texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
const tcu::Vec4 referenceValue = effectiveView.gatherOffsets(samplerParams.sampler, texCoord.x(), texCoord.y(), 0, glu::getDefaultGatherOffsets());
const tcu::Vec4 referencePixel = referenceValue * samplerParams.colorScale + samplerParams.colorBias;
const tcu::Vec4 resultPixel = renderedFrame.getPixel(px, py);
const tcu::Vec4 resultValue = (resultPixel - samplerParams.colorBias) / samplerParams.colorScale;
reference.setPixel(px, py, tcu::toRGBAMasked(referenceValue, fbColormask));
if (tcu::boolAny(tcu::logicalAnd(lookupPrecision.colorMask,
tcu::greaterThan(tcu::absDiff(resultPixel, referencePixel),
lookupPrecision.colorThreshold))))
{
if (!tcu::isGatherOffsetsResultValid(effectiveView, samplerParams.sampler, lookupPrecision, texCoord, 0, glu::getDefaultGatherOffsets(), resultValue))
{
errorMask.setPixel(px, py, tcu::RGBA::red());
++numFailedPixels;
}
}
}
if (numFailedPixels > 0)
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
<< tcu::TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_testCtx.getLog() << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
return (numFailedPixels == 0);
}
bool TextureBorderClampTest::verifyTextureGatherCmpResult (const tcu::ConstPixelBufferAccess& renderedFrame,
const float* texCoordArray,
const glu::TextureTestUtil::ReferenceParams& samplerParams,
const tcu::TexComparePrecision& texComparePrecision,
const tcu::TexComparePrecision& lowQualityTexComparePrecision)
{
const tcu::Vec2 texCoords[4] =
{
tcu::Vec2(texCoordArray[0], texCoordArray[1]),
tcu::Vec2(texCoordArray[2], texCoordArray[3]),
tcu::Vec2(texCoordArray[4], texCoordArray[5]),
tcu::Vec2(texCoordArray[6], texCoordArray[7]),
};
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
const tcu::Texture2DView effectiveView = tcu::getEffectiveTextureView(m_texture->getRefTexture(), srcLevelStorage, samplerParams.sampler);
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
const tcu::BVec4 colorMask = glu::TextureTestUtil::getCompareMask(pixelFormat);
const deUint8 fbColormask = tcu::getColorMask(pixelFormat);
tcu::Surface reference (renderedFrame.getWidth(), renderedFrame.getHeight());
tcu::Surface errorMask (renderedFrame.getWidth(), renderedFrame.getHeight());
int numFailedPixels = 0;
bool lowQuality = false;
tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
for (int py = 0; py < reference.getHeight(); ++py)
for (int px = 0; px < reference.getWidth(); ++px)
{
const tcu::Vec2 viewportCoord = (tcu::Vec2((float)px, (float)py) + tcu::Vec2(0.5f)) / tcu::Vec2((float)reference.getWidth(), (float)reference.getHeight());
const tcu::Vec2 texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
const float refZ = samplerParams.ref;
const tcu::Vec4 referenceValue = effectiveView.gatherOffsetsCompare(samplerParams.sampler, refZ, texCoord.x(), texCoord.y(), glu::getDefaultGatherOffsets());
const tcu::Vec4 resultValue = renderedFrame.getPixel(px, py);
reference.setPixel(px, py, tcu::toRGBAMasked(referenceValue, fbColormask));
if (tcu::boolAny(tcu::logicalAnd(colorMask, tcu::notEqual(referenceValue, resultValue))))
{
if (!tcu::isGatherOffsetsCompareResultValid(effectiveView, samplerParams.sampler, texComparePrecision, texCoord, glu::getDefaultGatherOffsets(), refZ, resultValue))
{
lowQuality = true;
// fall back to low quality verification
if (!tcu::isGatherOffsetsCompareResultValid(effectiveView, samplerParams.sampler, lowQualityTexComparePrecision, texCoord, glu::getDefaultGatherOffsets(), refZ, resultValue))
{
errorMask.setPixel(px, py, tcu::RGBA::red());
++numFailedPixels;
}
}
}
}
if (numFailedPixels > 0)
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
else if (lowQuality)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << tcu::TestLog::EndMessage;
m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
}
m_testCtx.getLog() << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
<< tcu::TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_testCtx.getLog() << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
return (numFailedPixels == 0);
}
const glu::Texture2D* TextureBorderClampTest::getTexture (void) const
{
return m_texture.get();
}
deUint32 TextureBorderClampTest::getIterationSeed (const IterationConfig& config) const
{
tcu::SeedBuilder builder;
builder << std::string(getName())
<< m_iterationNdx
<< m_texFormat
<< config.minFilter << config.magFilter
<< m_texture->getRefTexture().getWidth() << m_texture->getRefTexture().getHeight();
return builder.get();
}
glu::TextureTestUtil::ReferenceParams TextureBorderClampTest::genSamplerParams (const IterationConfig& config) const
{
const tcu::TextureFormat texFormat = tcu::getEffectiveDepthStencilTextureFormat(m_texture->getRefTexture().getFormat(), m_sampleMode);
glu::TextureTestUtil::ReferenceParams refParams (glu::TextureTestUtil::TEXTURETYPE_2D);
refParams.sampler = glu::mapGLSampler(config.sWrapMode, config.tWrapMode, config.minFilter, config.magFilter);
refParams.sampler.borderColor = config.borderColor;
refParams.sampler.compare = (!m_useShadowSampler) ? (tcu::Sampler::COMPAREMODE_NONE) : (glu::mapGLCompareFunc(config.compareMode));
refParams.sampler.depthStencilMode = m_sampleMode;
refParams.lodMode = glu::TextureTestUtil::LODMODE_EXACT;
refParams.samplerType = (!m_useShadowSampler) ? (glu::TextureTestUtil::getSamplerType(texFormat)) : (glu::TextureTestUtil::SAMPLERTYPE_SHADOW);
refParams.colorScale = config.lookupScale;
refParams.colorBias = config.lookupBias;
refParams.ref = config.compareRef;
// compare can only be used with depth textures
if (!isDepthFormat(m_texFormat, m_sampleMode))
DE_ASSERT(refParams.sampler.compare == tcu::Sampler::COMPAREMODE_NONE);
// sampler type must match compare mode
DE_ASSERT(m_useShadowSampler == (config.compareMode != GL_NONE));
// in gather, weird mapping is most likely an error
if (m_samplingFunction == SAMPLE_GATHER)
{
DE_ASSERT(refParams.colorScale == tcu::Vec4(refParams.colorScale.x()));
DE_ASSERT(refParams.colorBias == tcu::Vec4(refParams.colorBias.x()));
}
return refParams;
}
glu::ShaderProgram* TextureBorderClampTest::genGatherProgram (void) const
{
const std::string glslVersionDecl = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()));
const std::string vtxSource = glslVersionDecl + "\n"
"in highp vec4 a_position;\n"
"in highp vec2 a_texcoord;\n"
"out highp vec2 v_texcoord;\n"
"void main()\n"
"{\n"
" gl_Position = a_position;\n"
" v_texcoord = a_texcoord;\n"
"}\n";
const char* samplerType;
const char* lookup;
std::ostringstream fragSource;
if (m_useShadowSampler)
{
samplerType = "sampler2DShadow";
lookup = "textureGather(u_sampler, v_texcoord, u_ref)";
}
else
{
switch (m_channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
samplerType = "sampler2D";
lookup = "textureGather(u_sampler, v_texcoord)";
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
samplerType = "isampler2D";
lookup = "vec4(textureGather(u_sampler, v_texcoord))";
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
samplerType = "usampler2D";
lookup = "vec4(textureGather(u_sampler, v_texcoord))";
break;
default:
samplerType = "";
lookup = "";
DE_ASSERT(false);
}
}
fragSource << glslVersionDecl + "\n"
"uniform highp " << samplerType << " u_sampler;\n"
"uniform highp vec4 u_colorScale;\n"
"uniform highp vec4 u_colorBias;\n"
<< ((m_useShadowSampler) ? ("uniform highp float u_ref;\n") : (""))
<< "in highp vec2 v_texcoord;\n"
"layout(location=0) out highp vec4 o_color;\n"
"void main()\n"
"{\n"
" o_color = " << lookup << " * u_colorScale + u_colorBias;\n"
"}\n";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vtxSource) << glu::FragmentSource(fragSource.str()));
}
class TextureBorderClampFormatCase : public TextureBorderClampTest
{
public:
TextureBorderClampFormatCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
StateType stateType,
SizeType sizeType,
deUint32 filter,
SamplingFunction samplingFunction);
private:
void init (void);
int getNumIterations (void) const;
IterationConfig getIteration (int ndx) const;
const SizeType m_sizeType;
const deUint32 m_filter;
std::vector<IterationConfig> m_iterations;
};
TextureBorderClampFormatCase::TextureBorderClampFormatCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
StateType stateType,
SizeType sizeType,
deUint32 filter,
SamplingFunction samplingFunction)
: TextureBorderClampTest(context,
name,
description,
texFormat,
mode,
stateType,
(sizeType == SIZE_POT) ? (32) : (17),
(sizeType == SIZE_POT) ? (16) : (31),
samplingFunction)
, m_sizeType (sizeType)
, m_filter (filter)
{
if (m_sizeType == SIZE_POT)
DE_ASSERT(deIsPowerOfTwo32(m_texWidth) && deIsPowerOfTwo32(m_texHeight));
else
DE_ASSERT(!deIsPowerOfTwo32(m_texWidth) && !deIsPowerOfTwo32(m_texHeight));
if (glu::isCompressedFormat(texFormat))
{
const tcu::CompressedTexFormat compressedFormat = glu::mapGLCompressedTexFormat(texFormat);
const tcu::IVec3 blockPixelSize = tcu::getBlockPixelSize(compressedFormat);
// is (not) multiple of a block size
if (m_sizeType == SIZE_POT)
DE_ASSERT((m_texWidth % blockPixelSize.x()) == 0 && (m_texHeight % blockPixelSize.y()) == 0);
else
DE_ASSERT((m_texWidth % blockPixelSize.x()) != 0 && (m_texHeight % blockPixelSize.y()) != 0);
DE_UNREF(blockPixelSize);
}
}
void TextureBorderClampFormatCase::init (void)
{
TextureBorderClampTest::init();
// \note TextureBorderClampTest::init() creates texture
const tcu::TextureFormat texFormat = tcu::getEffectiveDepthStencilTextureFormat(getTexture()->getRefTexture().getFormat(), m_sampleMode);
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(texFormat);
// iterations
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-1.5f, -3.0f);
iteration.p1 = tcu::Vec2( 1.5f, 2.5f);
iteration.borderColor = mapToFormatColorRepresentable(texFormat, tcu::Vec4(0.3f, 0.7f, 0.2f, 0.5f));
m_iterations.push_back(iteration);
}
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.5f, 0.75f);
iteration.p1 = tcu::Vec2(0.25f, 1.25f);
iteration.borderColor = mapToFormatColorRepresentable(texFormat, tcu::Vec4(0.9f, 0.2f, 0.4f, 0.6f));
m_iterations.push_back(iteration);
}
// common parameters
for (int ndx = 0; ndx < (int)m_iterations.size(); ++ndx)
{
IterationConfig& iteration = m_iterations[ndx];
if (m_samplingFunction == SAMPLE_GATHER)
{
iteration.lookupScale = tcu::Vec4(texFormatInfo.lookupScale.x());
iteration.lookupBias = tcu::Vec4(texFormatInfo.lookupBias.x());
}
else
{
iteration.lookupScale = texFormatInfo.lookupScale;
iteration.lookupBias = texFormatInfo.lookupBias;
}
iteration.minFilter = m_filter;
iteration.magFilter = m_filter;
iteration.sWrapMode = GL_CLAMP_TO_BORDER;
iteration.tWrapMode = GL_CLAMP_TO_BORDER;
iteration.compareMode = GL_NONE;
iteration.compareRef = 0.0f;
}
}
int TextureBorderClampFormatCase::getNumIterations (void) const
{
return (int)m_iterations.size();
}
TextureBorderClampTest::IterationConfig TextureBorderClampFormatCase::getIteration (int ndx) const
{
return m_iterations[ndx];
}
class TextureBorderClampRangeClampCase : public TextureBorderClampTest
{
public:
TextureBorderClampRangeClampCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
deUint32 filter);
private:
void init (void);
int getNumIterations (void) const;
IterationConfig getIteration (int ndx) const;
const deUint32 m_filter;
std::vector<IterationConfig> m_iterations;
};
TextureBorderClampRangeClampCase::TextureBorderClampRangeClampCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
deUint32 filter)
: TextureBorderClampTest(context, name, description, texFormat, mode, TextureBorderClampTest::STATE_TEXTURE_PARAM, 8, 32, SAMPLE_FILTER)
, m_filter (filter)
{
}
void TextureBorderClampRangeClampCase::init (void)
{
TextureBorderClampTest::init();
const tcu::TextureFormat texFormat = tcu::getEffectiveDepthStencilTextureFormat(getTexture()->getRefTexture().getFormat(), m_sampleMode);
const bool isDepth = isDepthFormat(m_texFormat, m_sampleMode);
const bool isFloat = m_channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
const bool isFixed = m_channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || m_channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
const bool isPureInteger = m_channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || m_channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
if (isDepth || isFloat)
{
// infinities are commonly used values on depth/float borders
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-1.2f, -3.0f);
iteration.p1 = tcu::Vec2( 1.2f, 2.5f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(std::numeric_limits<float>::infinity()));
iteration.lookupScale = tcu::Vec4(0.5f); // scale & bias to [0.25, 0.5] range to make out-of-range values visible
iteration.lookupBias = tcu::Vec4(0.25f);
iteration.description = "border value infinity";
m_iterations.push_back(iteration);
}
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.25f, -0.75f);
iteration.p1 = tcu::Vec2( 2.25f, 1.25f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(-std::numeric_limits<float>::infinity()));
iteration.lookupScale = tcu::Vec4(0.5f);
iteration.lookupBias = tcu::Vec4(0.25f);
iteration.description = "border value negative infinity";
m_iterations.push_back(iteration);
}
}
else if (isPureInteger)
{
const tcu::IVec4 numBits = tcu::getTextureFormatBitDepth(texFormat);
const bool isSigned = m_channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
// can't overflow 32bit integers with 32bit integers
for (int ndx = 0; ndx < 4; ++ndx)
DE_ASSERT(numBits[ndx] == 0 || numBits[ndx] == 8 || numBits[ndx] == 16);
const tcu::IVec4 minValue = getNBitIntegerVec4MinValue(isSigned, numBits);
const tcu::IVec4 maxValue = getNBitIntegerVec4MaxValue(isSigned, numBits);
const tcu::IVec4 valueRange = maxValue - minValue;
const tcu::IVec4 divSafeRange ((valueRange[0]==0) ? (1) : (valueRange[0]),
(valueRange[1]==0) ? (1) : (valueRange[1]),
(valueRange[2]==0) ? (1) : (valueRange[2]),
(valueRange[3]==0) ? (1) : (valueRange[3]));
// format max
{
const tcu::IVec4 value = maxValue + tcu::IVec4(1);
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-1.2f, -3.0f);
iteration.p1 = tcu::Vec2( 1.2f, 2.5f);
iteration.borderColor = (isSigned) ? (rr::GenericVec4(value)) : (rr::GenericVec4(value.cast<deUint32>()));
iteration.lookupScale = tcu::Vec4(0.5f) / divSafeRange.cast<float>();
iteration.lookupBias = (isSigned) ? (tcu::Vec4(0.5f)) : (tcu::Vec4(0.25f));
iteration.description = "border values one larger than maximum";
m_iterations.push_back(iteration);
}
// format min
if (isSigned)
{
const tcu::IVec4 value = minValue - tcu::IVec4(1);
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.25f, -0.75f);
iteration.p1 = tcu::Vec2( 2.25f, 1.25f);
iteration.borderColor = rr::GenericVec4(value);
iteration.lookupScale = tcu::Vec4(0.5f) / divSafeRange.cast<float>();
iteration.lookupBias = tcu::Vec4(0.5f);
iteration.description = "border values one less than minimum";
m_iterations.push_back(iteration);
}
// (u)int32 max
{
const tcu::IVec4 value = (isSigned) ? (tcu::IVec4(std::numeric_limits<deInt32>::max())) : (tcu::IVec4(std::numeric_limits<deUint32>::max()));
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-1.6f, -2.1f);
iteration.p1 = tcu::Vec2( 1.2f, 3.5f);
iteration.borderColor = (isSigned) ? (rr::GenericVec4(value)) : (rr::GenericVec4(value.cast<deUint32>()));
iteration.lookupScale = tcu::Vec4(0.5f) / divSafeRange.cast<float>();
iteration.lookupBias = tcu::Vec4(0.25f);
iteration.description = "border values 32-bit maximum";
m_iterations.push_back(iteration);
}
// int32 min
if (isSigned)
{
const tcu::IVec4 value = tcu::IVec4(std::numeric_limits<deInt32>::min());
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-2.6f, -4.0f);
iteration.p1 = tcu::Vec2( 1.1f, 1.5f);
iteration.borderColor = rr::GenericVec4(value);
iteration.lookupScale = tcu::Vec4(0.5f) / divSafeRange.cast<float>();
iteration.lookupBias = tcu::Vec4(0.25f);
iteration.description = "border values 0";
m_iterations.push_back(iteration);
}
}
else if (isFixed)
{
const bool isSigned = m_channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;;
const tcu::Vec4 lookupBias = (isSigned) ? (tcu::Vec4(0.5f)) : (tcu::Vec4(0.25f)); // scale & bias to [0.25, 0.5] range to make out-of-range values visible
const tcu::Vec4 lookupScale = (isSigned) ? (tcu::Vec4(0.25f)) : (tcu::Vec4(0.5f));
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-1.2f, -3.0f);
iteration.p1 = tcu::Vec2( 1.2f, 2.5f);
iteration.borderColor = mapToFormatColorUnits(texFormat, tcu::Vec4(1.1f, 1.3f, 2.2f, 1.3f));
iteration.lookupScale = lookupScale;
iteration.lookupBias = lookupBias;
iteration.description = "border values larger than maximum";
m_iterations.push_back(iteration);
}
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.25f, -0.75f);
iteration.p1 = tcu::Vec2( 2.25f, 1.25f);
iteration.borderColor = mapToFormatColorUnits(texFormat, tcu::Vec4(-0.2f, -0.9f, -2.4f, -0.6f));
iteration.lookupScale = lookupScale;
iteration.lookupBias = lookupBias;
iteration.description = "border values less than minimum";
m_iterations.push_back(iteration);
}
}
else
DE_ASSERT(false);
// common parameters
for (int ndx = 0; ndx < (int)m_iterations.size(); ++ndx)
{
IterationConfig& iteration = m_iterations[ndx];
iteration.minFilter = m_filter;
iteration.magFilter = m_filter;
iteration.sWrapMode = GL_CLAMP_TO_BORDER;
iteration.tWrapMode = GL_CLAMP_TO_BORDER;
iteration.compareMode = GL_NONE;
iteration.compareRef = 0.0f;
}
}
int TextureBorderClampRangeClampCase::getNumIterations (void) const
{
return (int)m_iterations.size();
}
TextureBorderClampTest::IterationConfig TextureBorderClampRangeClampCase::getIteration (int ndx) const
{
return m_iterations[ndx];
}
class TextureBorderClampPerAxisCase2D : public TextureBorderClampTest
{
public:
TextureBorderClampPerAxisCase2D (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
SizeType sizeType,
deUint32 filter,
deUint32 texSWrap,
deUint32 texTWrap,
SamplingFunction samplingFunction);
private:
void init (void);
int getNumIterations (void) const;
IterationConfig getIteration (int ndx) const;
const deUint32 m_texSWrap;
const deUint32 m_texTWrap;
const deUint32 m_filter;
std::vector<IterationConfig> m_iterations;
};
TextureBorderClampPerAxisCase2D::TextureBorderClampPerAxisCase2D (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode mode,
SizeType sizeType,
deUint32 filter,
deUint32 texSWrap,
deUint32 texTWrap,
SamplingFunction samplingFunction)
: TextureBorderClampTest(context,
name,
description,
texFormat,
mode,
TextureBorderClampTest::STATE_TEXTURE_PARAM,
(sizeType == SIZE_POT) ? (16) : (7),
(sizeType == SIZE_POT) ? (8) : (9),
samplingFunction)
, m_texSWrap (texSWrap)
, m_texTWrap (texTWrap)
, m_filter (filter)
{
}
void TextureBorderClampPerAxisCase2D::init (void)
{
TextureBorderClampTest::init();
// \note TextureBorderClampTest::init() creates texture
const tcu::TextureFormat texFormat = tcu::getEffectiveDepthStencilTextureFormat(getTexture()->getRefTexture().getFormat(), m_sampleMode);
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(texFormat);
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.25f, -0.75f);
iteration.p1 = tcu::Vec2( 2.25f, 1.25f);
iteration.borderColor = mapToFormatColorRepresentable(texFormat, tcu::Vec4(0.4f, 0.9f, 0.1f, 0.2f));
if (m_samplingFunction == SAMPLE_GATHER)
{
iteration.lookupScale = tcu::Vec4(texFormatInfo.lookupScale.x());
iteration.lookupBias = tcu::Vec4(texFormatInfo.lookupBias.x());
}
else
{
iteration.lookupScale = texFormatInfo.lookupScale;
iteration.lookupBias = texFormatInfo.lookupBias;
}
iteration.minFilter = m_filter;
iteration.magFilter = m_filter;
iteration.sWrapMode = m_texSWrap;
iteration.tWrapMode = m_texTWrap;
iteration.compareMode = GL_NONE;
iteration.compareRef = 0.0f;
m_iterations.push_back(iteration);
}
int TextureBorderClampPerAxisCase2D::getNumIterations (void) const
{
return (int)m_iterations.size();
}
TextureBorderClampTest::IterationConfig TextureBorderClampPerAxisCase2D::getIteration (int ndx) const
{
return m_iterations[ndx];
}
class TextureBorderClampDepthCompareCase : public TextureBorderClampTest
{
public:
TextureBorderClampDepthCompareCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
SizeType sizeType,
deUint32 filter,
SamplingFunction samplingFunction);
private:
void init (void);
int getNumIterations (void) const;
IterationConfig getIteration (int ndx) const;
const deUint32 m_filter;
std::vector<IterationConfig> m_iterations;
};
TextureBorderClampDepthCompareCase::TextureBorderClampDepthCompareCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
SizeType sizeType,
deUint32 filter,
SamplingFunction samplingFunction)
: TextureBorderClampTest(context,
name,
description,
texFormat,
tcu::Sampler::MODE_DEPTH,
TextureBorderClampTest::STATE_TEXTURE_PARAM,
(sizeType == SIZE_POT) ? (32) : (13),
(sizeType == SIZE_POT) ? (16) : (17),
samplingFunction,
FLAG_USE_SHADOW_SAMPLER)
, m_filter (filter)
{
}
void TextureBorderClampDepthCompareCase::init (void)
{
TextureBorderClampTest::init();
// 0.5 <= 0.7
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.15f, -0.35f);
iteration.p1 = tcu::Vec2( 1.25f, 1.1f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(0.7f, 0.0f, 0.0f, 0.0f));
iteration.description = "Border color in [0, 1] range";
iteration.compareMode = GL_LEQUAL;
iteration.compareRef = 0.5f;
m_iterations.push_back(iteration);
}
// 1.5 <= 1.0
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.15f, -0.35f);
iteration.p1 = tcu::Vec2( 1.25f, 1.1f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(1.5f, 0.0f, 0.0f, 0.0f));
iteration.description = "Border color > 1, should be clamped";
iteration.compareMode = GL_LEQUAL;
iteration.compareRef = 1.0f;
m_iterations.push_back(iteration);
}
// -0.5 >= 0.0
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.15f, -0.35f);
iteration.p1 = tcu::Vec2( 1.25f, 1.1f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(-0.5f, 0.0f, 0.0f, 0.0f));
iteration.description = "Border color < 0, should be clamped";
iteration.compareMode = GL_GEQUAL;
iteration.compareRef = 0.0f;
m_iterations.push_back(iteration);
}
// inf < 1.25
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.15f, -0.35f);
iteration.p1 = tcu::Vec2( 1.25f, 1.1f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(std::numeric_limits<float>::infinity(), 0.0f, 0.0f, 0.0f));
iteration.description = "Border color == inf, should be clamped; ref > 1";
iteration.compareMode = GL_LESS;
iteration.compareRef = 1.25f;
m_iterations.push_back(iteration);
}
// -inf > -0.5
{
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.15f, -0.35f);
iteration.p1 = tcu::Vec2( 1.25f, 1.1f);
iteration.borderColor = rr::GenericVec4(tcu::Vec4(-std::numeric_limits<float>::infinity(), 0.0f, 0.0f, 0.0f));
iteration.description = "Border color == inf, should be clamped; ref < 0";
iteration.compareMode = GL_GREATER;
iteration.compareRef = -0.5f;
m_iterations.push_back(iteration);
}
// common parameters
for (int ndx = 0; ndx < (int)m_iterations.size(); ++ndx)
{
IterationConfig& iteration = m_iterations[ndx];
iteration.lookupScale = tcu::Vec4(1.0);
iteration.lookupBias = tcu::Vec4(0.0);
iteration.minFilter = m_filter;
iteration.magFilter = m_filter;
iteration.sWrapMode = GL_CLAMP_TO_BORDER;
iteration.tWrapMode = GL_CLAMP_TO_BORDER;
}
}
int TextureBorderClampDepthCompareCase::getNumIterations (void) const
{
return (int)m_iterations.size();
}
TextureBorderClampTest::IterationConfig TextureBorderClampDepthCompareCase::getIteration (int ndx) const
{
return m_iterations[ndx];
}
class TextureBorderClampUnusedChannelCase : public TextureBorderClampTest
{
public:
TextureBorderClampUnusedChannelCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode depthStencilMode);
private:
void init (void);
int getNumIterations (void) const;
IterationConfig getIteration (int ndx) const;
std::vector<IterationConfig> m_iterations;
};
TextureBorderClampUnusedChannelCase::TextureBorderClampUnusedChannelCase (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
tcu::Sampler::DepthStencilMode depthStencilMode)
: TextureBorderClampTest(context,
name,
description,
texFormat,
depthStencilMode,
TextureBorderClampTest::STATE_TEXTURE_PARAM,
8,
8,
SAMPLE_FILTER)
{
}
static rr::GenericVec4 selectComponents (const rr::GenericVec4& trueComponents, const rr::GenericVec4& falseComponents, const tcu::BVec4& m)
{
return rr::GenericVec4(tcu::select(trueComponents.get<deUint32>(), falseComponents.get<deUint32>(), m));
}
void TextureBorderClampUnusedChannelCase::init (void)
{
TextureBorderClampTest::init();
// \note TextureBorderClampTest::init() creates texture
const tcu::TextureFormat texFormat = tcu::getEffectiveDepthStencilTextureFormat(getTexture()->getRefTexture().getFormat(), m_sampleMode);
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(texFormat);
const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(texFormat);
const float maxChannelValue = (channelMask[0]) ? (texFormatInfo.valueMax[0])
: (channelMask[1]) ? (texFormatInfo.valueMax[1])
: (channelMask[2]) ? (texFormatInfo.valueMax[2])
: (texFormatInfo.valueMax[3]);
const rr::GenericVec4 effectiveColors = mapToFormatColorRepresentable(texFormat, tcu::Vec4(0.6f));
rr::GenericVec4 nonEffectiveColors;
switch (m_channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
nonEffectiveColors = rr::GenericVec4(tcu::Vec4(maxChannelValue * 0.8f));
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
nonEffectiveColors = rr::GenericVec4(tcu::Vec4(maxChannelValue * 0.8f).cast<deInt32>());
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
nonEffectiveColors = rr::GenericVec4(tcu::Vec4(maxChannelValue * 0.8f).cast<deUint32>());
break;
default:
DE_ASSERT(false);
}
IterationConfig iteration;
iteration.p0 = tcu::Vec2(-0.25f, -0.75f);
iteration.p1 = tcu::Vec2( 2.25f, 1.25f);
iteration.borderColor = selectComponents(effectiveColors, nonEffectiveColors, channelMask);
iteration.lookupScale = texFormatInfo.lookupScale;
iteration.lookupBias = texFormatInfo.lookupBias;
iteration.minFilter = GL_NEAREST;
iteration.magFilter = GL_NEAREST;
iteration.sWrapMode = GL_CLAMP_TO_BORDER;
iteration.tWrapMode = GL_CLAMP_TO_BORDER;
iteration.compareMode = GL_NONE;
iteration.compareRef = 0.0f;
iteration.description = "Setting values to unused border color components";
m_iterations.push_back(iteration);
}
int TextureBorderClampUnusedChannelCase::getNumIterations (void) const
{
return (int)m_iterations.size();
}
TextureBorderClampTest::IterationConfig TextureBorderClampUnusedChannelCase::getIteration (int ndx) const
{
return m_iterations[ndx];
}
class TextureBorderClampPerAxisCase3D : public TestCase
{
public:
TextureBorderClampPerAxisCase3D (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
SizeType size,
deUint32 filter,
deUint32 sWrap,
deUint32 tWrap,
deUint32 rWrap);
private:
void init (void);
void deinit (void);
IterateResult iterate (void);
void renderTo (tcu::Surface& surface,
const glu::TextureTestUtil::ReferenceParams& samplerParams);
void logParams (const glu::TextureTestUtil::ReferenceParams& samplerParams);
void verifyImage (const tcu::Surface& image,
const glu::TextureTestUtil::ReferenceParams& samplerParams);
glu::TextureTestUtil::ReferenceParams getSamplerParams (void) const;
deUint32 getCaseSeed (void) const;
enum
{
VIEWPORT_WIDTH = 128,
VIEWPORT_HEIGHT = 128,
};
const deUint32 m_texFormat;
const tcu::TextureChannelClass m_channelClass;
const tcu::IVec3 m_size;
const deUint32 m_filter;
const deUint32 m_sWrap;
const deUint32 m_tWrap;
const deUint32 m_rWrap;
de::MovePtr<glu::Texture3D> m_texture;
de::MovePtr<gls::TextureTestUtil::TextureRenderer> m_renderer;
rr::GenericVec4 m_borderColor;
std::vector<float> m_texCoords;
tcu::Vec4 m_lookupScale;
tcu::Vec4 m_lookupBias;
};
TextureBorderClampPerAxisCase3D::TextureBorderClampPerAxisCase3D (Context& context,
const char* name,
const char* description,
deUint32 texFormat,
SizeType size,
deUint32 filter,
deUint32 sWrap,
deUint32 tWrap,
deUint32 rWrap)
: TestCase (context, name, description)
, m_texFormat (texFormat)
, m_channelClass (getFormatChannelClass(texFormat, tcu::Sampler::MODE_LAST))
, m_size ((size == SIZE_POT) ? (tcu::IVec3(8, 16, 4)) : (tcu::IVec3(13, 5, 7)))
, m_filter (filter)
, m_sWrap (sWrap)
, m_tWrap (tWrap)
, m_rWrap (rWrap)
{
}
void TextureBorderClampPerAxisCase3D::init (void)
{
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_border_clamp"))
throw tcu::NotSupportedError("Test requires GL_EXT_texture_border_clamp extension");
if (glu::isCompressedFormat(m_texFormat) &&
!supportsES32 &&
tcu::isAstcFormat(glu::mapGLCompressedTexFormat(m_texFormat)) &&
!m_context.getContextInfo().isExtensionSupported("GL_KHR_texture_compression_astc_ldr"))
{
throw tcu::NotSupportedError("Test requires GL_KHR_texture_compression_astc_ldr extension");
}
if (m_texFormat == GL_BGRA && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_format_BGRA8888"))
throw tcu::NotSupportedError("Test requires GL_EXT_texture_format_BGRA8888 extension");
if (m_context.getRenderTarget().getWidth() < VIEWPORT_WIDTH ||
m_context.getRenderTarget().getHeight() < VIEWPORT_HEIGHT)
{
throw tcu::NotSupportedError("Test requires " + de::toString<int>(VIEWPORT_WIDTH) + "x" + de::toString<int>(VIEWPORT_HEIGHT) + " viewport");
}
// resources
m_texture = genDefaultTexture<glu::Texture3D>(m_context.getRenderContext(), m_context.getContextInfo(), m_texFormat, m_size);
m_renderer = de::MovePtr<gls::TextureTestUtil::TextureRenderer>(new gls::TextureTestUtil::TextureRenderer(m_context.getRenderContext(), m_testCtx.getLog(), glslVersion, glu::PRECISION_HIGHP));
// texture info
m_testCtx.getLog() << tcu::TestLog::Message
<< "Created 3D texture with format " << glu::getTextureFormatName(m_texFormat)
<< ", size (" << m_texture->getRefTexture().getWidth() << ", " << m_texture->getRefTexture().getHeight() << ", " << m_texture->getRefTexture().getDepth() << ")\n"
<< tcu::TestLog::EndMessage;
// tex coord
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Setting tex coords bottom-left: (-1, -1, -1.5), top-right (2, 2, 2.5)\n"
<< tcu::TestLog::EndMessage;
m_texCoords.resize(4*3);
m_texCoords[0] = -1.0f; m_texCoords[ 1] = -1.0f; m_texCoords[ 2] = -1.5f;
m_texCoords[3] = -1.0f; m_texCoords[ 4] = 2.0f; m_texCoords[ 5] = 0.5f;
m_texCoords[6] = 2.0f; m_texCoords[ 7] = -1.0f; m_texCoords[ 8] = 0.5f;
m_texCoords[9] = 2.0f; m_texCoords[10] = 2.0f; m_texCoords[11] = 2.5f;
}
// set render params
{
const tcu::TextureFormat texFormat = m_texture->getRefTexture().getFormat();
const tcu::TextureFormatInfo texFormatInfo = tcu::getTextureFormatInfo(texFormat);
m_borderColor = mapToFormatColorRepresentable(texFormat, tcu::Vec4(0.2f, 0.6f, 0.9f, 0.4f));
m_lookupScale = texFormatInfo.lookupScale;
m_lookupBias = texFormatInfo.lookupBias;
}
}
void TextureBorderClampPerAxisCase3D::deinit (void)
{
m_texture.clear();
m_renderer.clear();
}
TextureBorderClampPerAxisCase3D::IterateResult TextureBorderClampPerAxisCase3D::iterate (void)
{
tcu::Surface renderedFrame (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
const glu::TextureTestUtil::ReferenceParams samplerParams = getSamplerParams();
logParams(samplerParams);
renderTo(renderedFrame, samplerParams);
verifyImage(renderedFrame, samplerParams);
return STOP;
}
void TextureBorderClampPerAxisCase3D::logParams (const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
const std::string borderColorString = (m_channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) ? (de::toString(m_borderColor.get<deInt32>()))
: (m_channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) ? (de::toString(m_borderColor.get<deUint32>()))
: (de::toString(m_borderColor.get<float>()));
m_testCtx.getLog() << tcu::TestLog::Message
<< "Border color is " << borderColorString << "\n"
<< "Texture lookup bias: " << samplerParams.colorBias << "\n"
<< "Texture lookup scale: " << samplerParams.colorScale << "\n"
<< "Filter: " << glu::getTextureFilterName(m_filter) << "\n"
<< "Wrap mode: s = " << glu::getRepeatModeStr(m_sWrap)
<< ", t = " << glu::getRepeatModeStr(m_tWrap)
<< ", r = " << glu::getRepeatModeStr(m_rWrap) << "\n"
<< tcu::TestLog::EndMessage;
}
void TextureBorderClampPerAxisCase3D::renderTo (tcu::Surface& surface,
const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const gls::TextureTestUtil::RandomViewport viewport (m_context.getRenderTarget(), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, getCaseSeed());
// Bind to unit 0.
gl.activeTexture(GL_TEXTURE0);
gl.bindTexture(GL_TEXTURE_3D, m_texture->getGLTexture());
// Setup filtering and wrap modes.
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(samplerParams.sampler.wrapS));
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(samplerParams.sampler.wrapT));
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, glu::getGLWrapMode(samplerParams.sampler.wrapR));
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(samplerParams.sampler.minFilter));
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(samplerParams.sampler.magFilter));
switch (m_channelClass)
{
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
gl.texParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, m_borderColor.getAccess<float>());
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
gl.texParameterIiv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, m_borderColor.getAccess<deInt32>());
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
gl.texParameterIuiv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, m_borderColor.getAccess<deUint32>());
break;
default:
DE_ASSERT(false);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
m_renderer->renderQuad(0, &m_texCoords[0], samplerParams);
glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, surface.getAccess());
}
void TextureBorderClampPerAxisCase3D::verifyImage (const tcu::Surface& renderedFrame,
const glu::TextureTestUtil::ReferenceParams& samplerParams)
{
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
const int colorErrorBits = 2;
const tcu::IVec4 colorBits = tcu::max(glu::TextureTestUtil::getBitsVec(pixelFormat) - tcu::IVec4(colorErrorBits), tcu::IVec4(0));
tcu::Surface reference (renderedFrame.getWidth(), renderedFrame.getHeight());
tcu::Surface errorMask (renderedFrame.getWidth(), renderedFrame.getHeight());
tcu::LodPrecision lodPrecision;
tcu::LookupPrecision lookupPrecision;
int numFailedPixels;
lodPrecision.derivateBits = 18;
lodPrecision.lodBits = 5;
lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / samplerParams.colorScale;
lookupPrecision.coordBits = tcu::IVec3(20,20,0);
lookupPrecision.uvwBits = tcu::IVec3(5,5,0);
lookupPrecision.colorMask = glu::TextureTestUtil::getCompareMask(pixelFormat);
glu::TextureTestUtil::sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), m_texture->getRefTexture(), &m_texCoords[0], samplerParams);
numFailedPixels = glu::TextureTestUtil::computeTextureLookupDiff(renderedFrame.getAccess(), reference.getAccess(), errorMask.getAccess(), m_texture->getRefTexture(),
&m_texCoords[0], samplerParams, lookupPrecision, lodPrecision, m_testCtx.getWatchDog());
if (numFailedPixels > 0)
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
<< tcu::TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_testCtx.getLog() << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
if (numFailedPixels == 0)
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
}
glu::TextureTestUtil::ReferenceParams TextureBorderClampPerAxisCase3D::getSamplerParams (void) const
{
const tcu::TextureFormat texFormat = m_texture->getRefTexture().getFormat();
glu::TextureTestUtil::ReferenceParams refParams (glu::TextureTestUtil::TEXTURETYPE_3D);
refParams.sampler = glu::mapGLSampler(m_sWrap, m_tWrap, m_rWrap, m_filter, m_filter);
refParams.sampler.borderColor = m_borderColor;
refParams.lodMode = glu::TextureTestUtil::LODMODE_EXACT;
refParams.samplerType = glu::TextureTestUtil::getSamplerType(texFormat);
refParams.colorScale = m_lookupScale;
refParams.colorBias = m_lookupBias;
return refParams;
}
deUint32 TextureBorderClampPerAxisCase3D::getCaseSeed (void) const
{
tcu::SeedBuilder builder;
builder << std::string(getName())
<< m_texFormat
<< m_filter
<< m_sWrap
<< m_tWrap
<< m_rWrap
<< m_texture->getRefTexture().getWidth()
<< m_texture->getRefTexture().getHeight()
<< m_texture->getRefTexture().getDepth();
return builder.get();
}
} // anonymous
TextureBorderClampTests::TextureBorderClampTests (Context& context)
: TestCaseGroup(context, "border_clamp", "EXT_texture_border_clamp tests")
{
}
TextureBorderClampTests::~TextureBorderClampTests (void)
{
}
void TextureBorderClampTests::init (void)
{
static const struct
{
const char* name;
deUint32 filter;
TextureBorderClampTest::SamplingFunction sampling;
} s_filters[] =
{
{ "nearest", GL_NEAREST, TextureBorderClampTest::SAMPLE_FILTER },
{ "linear", GL_LINEAR, TextureBorderClampTest::SAMPLE_FILTER },
{ "gather", GL_NEAREST, TextureBorderClampTest::SAMPLE_GATHER },
};
// .formats
{
static const struct
{
const char* name;
deUint32 format;
tcu::Sampler::DepthStencilMode mode;
} formats[] =
{
{ "luminance", GL_LUMINANCE, tcu::Sampler::MODE_LAST },
{ "alpha", GL_ALPHA, tcu::Sampler::MODE_LAST },
{ "luminance_alpha", GL_LUMINANCE_ALPHA, tcu::Sampler::MODE_LAST },
{ "bgra", GL_BGRA, tcu::Sampler::MODE_LAST },
{ "r8", GL_R8, tcu::Sampler::MODE_LAST },
{ "r8_snorm", GL_R8_SNORM, tcu::Sampler::MODE_LAST },
{ "rg8", GL_RG8, tcu::Sampler::MODE_LAST },
{ "rg8_snorm", GL_RG8_SNORM, tcu::Sampler::MODE_LAST },
{ "rgb8", GL_RGB8, tcu::Sampler::MODE_LAST },
{ "rgb8_snorm", GL_RGB8_SNORM, tcu::Sampler::MODE_LAST },
{ "rgb565", GL_RGB565, tcu::Sampler::MODE_LAST },
{ "rgba4", GL_RGBA4, tcu::Sampler::MODE_LAST },
{ "rgb5_a1", GL_RGB5_A1, tcu::Sampler::MODE_LAST },
{ "rgba8", GL_RGBA8, tcu::Sampler::MODE_LAST },
{ "rgba8_snorm", GL_RGBA8_SNORM, tcu::Sampler::MODE_LAST },
{ "rgb10_a2", GL_RGB10_A2, tcu::Sampler::MODE_LAST },
{ "rgb10_a2ui", GL_RGB10_A2UI, tcu::Sampler::MODE_LAST },
{ "srgb8", GL_SRGB8, tcu::Sampler::MODE_LAST },
{ "srgb8_alpha8", GL_SRGB8_ALPHA8, tcu::Sampler::MODE_LAST },
{ "r16f", GL_R16F, tcu::Sampler::MODE_LAST },
{ "rg16f", GL_RG16F, tcu::Sampler::MODE_LAST },
{ "rgb16f", GL_RGB16F, tcu::Sampler::MODE_LAST },
{ "rgba16f", GL_RGBA16F, tcu::Sampler::MODE_LAST },
{ "r32f", GL_R32F, tcu::Sampler::MODE_LAST },
{ "rg32f", GL_RG32F, tcu::Sampler::MODE_LAST },
{ "rgb32f", GL_RGB32F, tcu::Sampler::MODE_LAST },
{ "rgba32f", GL_RGBA32F, tcu::Sampler::MODE_LAST },
{ "r11f_g11f_b10f", GL_R11F_G11F_B10F, tcu::Sampler::MODE_LAST },
{ "rgb9_e5", GL_RGB9_E5, tcu::Sampler::MODE_LAST },
{ "r8i", GL_R8I, tcu::Sampler::MODE_LAST },
{ "r8ui", GL_R8UI, tcu::Sampler::MODE_LAST },
{ "r16i", GL_R16I, tcu::Sampler::MODE_LAST },
{ "r16ui", GL_R16UI, tcu::Sampler::MODE_LAST },
{ "r32i", GL_R32I, tcu::Sampler::MODE_LAST },
{ "r32ui", GL_R32UI, tcu::Sampler::MODE_LAST },
{ "rg8i", GL_RG8I, tcu::Sampler::MODE_LAST },
{ "rg8ui", GL_RG8UI, tcu::Sampler::MODE_LAST },
{ "rg16i", GL_RG16I, tcu::Sampler::MODE_LAST },
{ "rg16ui", GL_RG16UI, tcu::Sampler::MODE_LAST },
{ "rg32i", GL_RG32I, tcu::Sampler::MODE_LAST },
{ "rg32ui", GL_RG32UI, tcu::Sampler::MODE_LAST },
{ "rgb8i", GL_RGB8I, tcu::Sampler::MODE_LAST },
{ "rgb8ui", GL_RGB8UI, tcu::Sampler::MODE_LAST },
{ "rgb16i", GL_RGB16I, tcu::Sampler::MODE_LAST },
{ "rgb16ui", GL_RGB16UI, tcu::Sampler::MODE_LAST },
{ "rgb32i", GL_RGB32I, tcu::Sampler::MODE_LAST },
{ "rgb32ui", GL_RGB32UI, tcu::Sampler::MODE_LAST },
{ "rgba8i", GL_RGBA8I, tcu::Sampler::MODE_LAST },
{ "rgba8ui", GL_RGBA8UI, tcu::Sampler::MODE_LAST },
{ "rgba16i", GL_RGBA16I, tcu::Sampler::MODE_LAST },
{ "rgba16ui", GL_RGBA16UI, tcu::Sampler::MODE_LAST },
{ "rgba32i", GL_RGBA32I, tcu::Sampler::MODE_LAST },
{ "rgba32ui", GL_RGBA32UI, tcu::Sampler::MODE_LAST },
{ "depth_component16", GL_DEPTH_COMPONENT16, tcu::Sampler::MODE_DEPTH },
{ "depth_component24", GL_DEPTH_COMPONENT24, tcu::Sampler::MODE_DEPTH },
{ "depth_component32f", GL_DEPTH_COMPONENT32F, tcu::Sampler::MODE_DEPTH },
{ "stencil_index8", GL_STENCIL_INDEX8, tcu::Sampler::MODE_STENCIL },
{ "depth24_stencil8_sample_depth", GL_DEPTH24_STENCIL8, tcu::Sampler::MODE_DEPTH },
{ "depth32f_stencil8_sample_depth", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_DEPTH },
{ "depth24_stencil8_sample_stencil", GL_DEPTH24_STENCIL8, tcu::Sampler::MODE_STENCIL },
{ "depth32f_stencil8_sample_stencil", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_STENCIL },
{ "compressed_r11_eac", GL_COMPRESSED_R11_EAC, tcu::Sampler::MODE_LAST },
{ "compressed_signed_r11_eac", GL_COMPRESSED_SIGNED_R11_EAC, tcu::Sampler::MODE_LAST },
{ "compressed_rg11_eac", GL_COMPRESSED_RG11_EAC, tcu::Sampler::MODE_LAST },
{ "compressed_signed_rg11_eac", GL_COMPRESSED_SIGNED_RG11_EAC, tcu::Sampler::MODE_LAST },
{ "compressed_rgb8_etc2", GL_COMPRESSED_RGB8_ETC2, tcu::Sampler::MODE_LAST },
{ "compressed_srgb8_etc2", GL_COMPRESSED_SRGB8_ETC2, tcu::Sampler::MODE_LAST },
{ "compressed_rgb8_punchthrough_alpha1_etc2", GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, tcu::Sampler::MODE_LAST },
{ "compressed_srgb8_punchthrough_alpha1_etc2", GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, tcu::Sampler::MODE_LAST },
{ "compressed_rgba8_etc2_eac", GL_COMPRESSED_RGBA8_ETC2_EAC, tcu::Sampler::MODE_LAST },
{ "compressed_srgb8_alpha8_etc2_eac", GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, tcu::Sampler::MODE_LAST },
};
tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "Format tests");
addChild(formatsGroup);
// .format
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
{
const deUint32 format = formats[formatNdx].format;
const tcu::Sampler::DepthStencilMode sampleMode = formats[formatNdx].mode;
const bool isCompressed = glu::isCompressedFormat(format);
const bool coreFilterable = isCoreFilterableFormat(format, sampleMode);
tcu::TestCaseGroup* const formatGroup = new tcu::TestCaseGroup(m_testCtx, formats[formatNdx].name, "Format test");
formatsGroup->addChild(formatGroup);
// .nearest
// .linear
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(s_filters); ++filterNdx)
{
// [not-compressed]
// .size_pot
// .size_npot
// [compressed]
// .size_tile_multiple (also pot)
// .size_not_tile_multiple (also npot)
for (int sizeNdx = 0; sizeNdx < 2; ++sizeNdx)
{
const bool isNpotCase = (sizeNdx == 1);
const char* const sizePotName = (!isCompressed) ? ("size_pot") : ("size_tile_multiple");
const char* const sizeNpotName = (!isCompressed) ? ("size_npot") : ("size_not_tile_multiple");
const char* const sizeName = (isNpotCase) ? (sizeNpotName) : (sizePotName);
const SizeType sizeType = (isNpotCase) ? (SIZE_NPOT) : (SIZE_POT);
const std::string caseName = std::string() + s_filters[filterNdx].name + "_" + sizeName;
const deUint32 filter = s_filters[filterNdx].filter;
if (coreFilterable || !filterRequiresFilterability(filter))
formatGroup->addChild(new TextureBorderClampFormatCase(m_context,
caseName.c_str(),
"",
format,
sampleMode,
TextureBorderClampFormatCase::STATE_TEXTURE_PARAM,
sizeType,
filter,
s_filters[filterNdx].sampling));
}
}
}
}
// .range_clamp
{
static const struct
{
const char* name;
deUint32 format;
tcu::Sampler::DepthStencilMode mode;
} formats[] =
{
{ "unorm_color", GL_R8, tcu::Sampler::MODE_LAST },
{ "snorm_color", GL_R8_SNORM, tcu::Sampler::MODE_LAST },
{ "float_color", GL_RG32F, tcu::Sampler::MODE_LAST },
{ "int_color", GL_R8I, tcu::Sampler::MODE_LAST },
{ "uint_color", GL_R16UI, tcu::Sampler::MODE_LAST },
{ "srgb_color", GL_SRGB8_ALPHA8, tcu::Sampler::MODE_LAST },
{ "unorm_depth", GL_DEPTH_COMPONENT24, tcu::Sampler::MODE_DEPTH },
{ "float_depth", GL_DEPTH_COMPONENT32F, tcu::Sampler::MODE_DEPTH },
{ "uint_stencil", GL_STENCIL_INDEX8, tcu::Sampler::MODE_STENCIL },
{ "float_depth_uint_stencil_sample_depth", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_DEPTH },
{ "float_depth_uint_stencil_sample_stencil", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_STENCIL },
{ "unorm_depth_uint_stencil_sample_depth", GL_DEPTH24_STENCIL8, tcu::Sampler::MODE_DEPTH },
{ "unorm_depth_uint_stencil_sample_stencil", GL_DEPTH24_STENCIL8, tcu::Sampler::MODE_STENCIL },
{ "compressed_color", GL_COMPRESSED_RG11_EAC, tcu::Sampler::MODE_LAST },
};
tcu::TestCaseGroup* const rangeClampGroup = new tcu::TestCaseGroup(m_testCtx, "range_clamp", "Range clamp tests");
addChild(rangeClampGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(s_filters); ++filterNdx)
{
const deUint32 format = formats[formatNdx].format;
const tcu::Sampler::DepthStencilMode sampleMode = formats[formatNdx].mode;
const std::string caseName = std::string() + s_filters[filterNdx].name + "_" + formats[formatNdx].name;
const deUint32 filter = s_filters[filterNdx].filter;
const bool coreFilterable = isCoreFilterableFormat(format, sampleMode);
if (s_filters[filterNdx].sampling == TextureBorderClampTest::SAMPLE_GATHER)
continue;
if (coreFilterable || !filterRequiresFilterability(filter))
rangeClampGroup->addChild(new TextureBorderClampRangeClampCase(m_context, caseName.c_str(), "", format, sampleMode, filter));
}
}
// .sampler
{
static const struct
{
const char* name;
deUint32 format;
tcu::Sampler::DepthStencilMode mode;
} formats[] =
{
{ "unorm_color", GL_R8, tcu::Sampler::MODE_LAST },
{ "snorm_color", GL_R8_SNORM, tcu::Sampler::MODE_LAST },
{ "float_color", GL_RG32F, tcu::Sampler::MODE_LAST },
{ "int_color", GL_R8I, tcu::Sampler::MODE_LAST },
{ "uint_color", GL_R16UI, tcu::Sampler::MODE_LAST },
{ "unorm_depth", GL_DEPTH_COMPONENT24, tcu::Sampler::MODE_DEPTH },
{ "float_depth", GL_DEPTH_COMPONENT32F, tcu::Sampler::MODE_DEPTH },
{ "uint_stencil", GL_STENCIL_INDEX8, tcu::Sampler::MODE_STENCIL },
{ "compressed_color", GL_COMPRESSED_RG11_EAC, tcu::Sampler::MODE_LAST },
};
tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler param tests");
addChild(samplerGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
{
const deUint32 format = formats[formatNdx].format;
const tcu::Sampler::DepthStencilMode sampleMode = formats[formatNdx].mode;
const char* caseName = formats[formatNdx].name;
samplerGroup->addChild(new TextureBorderClampFormatCase(m_context,
caseName,
"",
format,
sampleMode,
TextureBorderClampFormatCase::STATE_SAMPLER_PARAM,
SIZE_POT,
GL_NEAREST,
TextureBorderClampFormatCase::SAMPLE_FILTER));
}
}
// .per_axis_wrap_mode
{
static const struct
{
const char* name;
bool is3D;
} targets[] =
{
{ "texture_2d", false },
{ "texture_3d", true },
};
static const struct
{
const char* name;
deUint32 format;
tcu::Sampler::DepthStencilMode mode;
bool supports3D;
} formats[] =
{
{ "unorm_color", GL_RG8, tcu::Sampler::MODE_LAST, true },
{ "snorm_color", GL_RG8_SNORM, tcu::Sampler::MODE_LAST, true },
{ "float_color", GL_R32F, tcu::Sampler::MODE_LAST, true },
{ "int_color", GL_RG16I, tcu::Sampler::MODE_LAST, true },
{ "uint_color", GL_R8UI, tcu::Sampler::MODE_LAST, true },
{ "unorm_depth", GL_DEPTH_COMPONENT16, tcu::Sampler::MODE_DEPTH, false },
{ "float_depth", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_DEPTH, false },
{ "uint_stencil", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_STENCIL, false },
{ "compressed_color", GL_COMPRESSED_RGB8_ETC2, tcu::Sampler::MODE_LAST, false },
};
static const struct
{
const char* name;
deUint32 sWrap;
deUint32 tWrap;
deUint32 rWrap;
bool is3D;
} wrapConfigs[] =
{
// 2d configs
{ "s_clamp_to_edge_t_clamp_to_border", GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_NONE, false },
{ "s_repeat_t_clamp_to_border", GL_REPEAT, GL_CLAMP_TO_BORDER, GL_NONE, false },
{ "s_mirrored_repeat_t_clamp_to_border", GL_MIRRORED_REPEAT, GL_CLAMP_TO_BORDER, GL_NONE, false },
// 3d configs
{ "s_clamp_to_border_t_clamp_to_border_r_clamp_to_border", GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, true },
{ "s_clamp_to_border_t_clamp_to_border_r_repeat", GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, GL_REPEAT, true },
{ "s_mirrored_repeat_t_clamp_to_border_r_repeat", GL_MIRRORED_REPEAT, GL_CLAMP_TO_BORDER, GL_REPEAT, true },
{ "s_repeat_t_mirrored_repeat_r_clamp_to_border", GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_BORDER, true },
};
tcu::TestCaseGroup* const perAxisGroup = new tcu::TestCaseGroup(m_testCtx, "per_axis_wrap_mode", "Per-axis wrapping modes");
addChild(perAxisGroup);
// .texture_nd
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
{
tcu::TestCaseGroup* const targetGroup = new tcu::TestCaseGroup(m_testCtx, targets[targetNdx].name, "Texture target test");
perAxisGroup->addChild(targetGroup);
// .format
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
{
if (targets[targetNdx].is3D && !formats[formatNdx].supports3D)
continue;
else
{
const deUint32 format = formats[formatNdx].format;
const tcu::Sampler::DepthStencilMode sampleMode = formats[formatNdx].mode;
const bool coreFilterable = isCoreFilterableFormat(format, sampleMode);
tcu::TestCaseGroup* const formatGroup = new tcu::TestCaseGroup(m_testCtx, formats[formatNdx].name, "Format test");
targetGroup->addChild(formatGroup);
// .linear
// .nearest
// .gather
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(s_filters); ++filterNdx)
{
const deUint32 filter = s_filters[filterNdx].filter;
if (!coreFilterable && filterRequiresFilterability(filter))
{
// skip linear on pure integers
continue;
}
else if (s_filters[filterNdx].sampling == TextureBorderClampTest::SAMPLE_GATHER && targets[targetNdx].is3D)
{
// skip gather on 3d
continue;
}
else
{
tcu::TestCaseGroup* const filteringGroup = new tcu::TestCaseGroup(m_testCtx, s_filters[filterNdx].name, "Tests with specific filter");
formatGroup->addChild(filteringGroup);
// .s_XXX_t_XXX(_r_XXX)
for (int wrapNdx = 0; wrapNdx < DE_LENGTH_OF_ARRAY(wrapConfigs); ++wrapNdx)
{
if (wrapConfigs[wrapNdx].is3D != targets[targetNdx].is3D)
continue;
else
{
for (int sizeNdx = 0; sizeNdx < 2; ++sizeNdx)
{
const char* const wrapName = wrapConfigs[wrapNdx].name;
const bool isNpotCase = (sizeNdx == 1);
const char* const sizeNameExtension = (isNpotCase) ? ("_npot") : ("_pot");
const SizeType size = (isNpotCase) ? (SIZE_NPOT) : (SIZE_POT);
if (!targets[targetNdx].is3D)
filteringGroup->addChild(new TextureBorderClampPerAxisCase2D(m_context,
(std::string() + wrapName + sizeNameExtension).c_str(),
"",
format,
sampleMode,
size,
filter,
wrapConfigs[wrapNdx].sWrap,
wrapConfigs[wrapNdx].tWrap,
s_filters[filterNdx].sampling));
else
{
DE_ASSERT(sampleMode == tcu::Sampler::MODE_LAST);
filteringGroup->addChild(new TextureBorderClampPerAxisCase3D(m_context,
(std::string() + wrapName + sizeNameExtension).c_str(),
"",
format,
size,
filter,
wrapConfigs[wrapNdx].sWrap,
wrapConfigs[wrapNdx].tWrap,
wrapConfigs[wrapNdx].rWrap));
}
}
}
}
}
}
}
}
}
}
// .depth_compare_mode
{
static const struct
{
const char* name;
deUint32 format;
} formats[] =
{
{ "depth_component16", GL_DEPTH_COMPONENT16 },
{ "depth_component24", GL_DEPTH_COMPONENT24 },
{ "depth24_stencil8", GL_DEPTH24_STENCIL8 },
{ "depth32f_stencil8", GL_DEPTH32F_STENCIL8 },
};
tcu::TestCaseGroup* const compareGroup = new tcu::TestCaseGroup(m_testCtx, "depth_compare_mode", "Tests depth compare mode");
addChild(compareGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
{
const deUint32 format = formats[formatNdx].format;
tcu::TestCaseGroup* const formatGroup = new tcu::TestCaseGroup(m_testCtx, formats[formatNdx].name, "Format test");
compareGroup->addChild(formatGroup);
// (format).(linear|nearest|gather)_(pot|npot)
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(s_filters); ++filterNdx)
for (int sizeNdx = 0; sizeNdx < 2; ++sizeNdx)
{
const bool isNpotCase = (sizeNdx == 1);
const char* const sizeName = (isNpotCase) ? ("size_npot") : ("size_pot");
const SizeType sizeType = (isNpotCase) ? (SIZE_NPOT) : (SIZE_POT);
const std::string caseName = std::string() + s_filters[filterNdx].name + "_" + sizeName;
const deUint32 filter = s_filters[filterNdx].filter;
formatGroup->addChild(new TextureBorderClampDepthCompareCase(m_context,
caseName.c_str(),
"",
format,
sizeType,
filter,
s_filters[filterNdx].sampling));
}
}
}
// unused channels (A in rgb, G in stencil etc.)
{
static const struct
{
const char* name;
deUint32 format;
tcu::Sampler::DepthStencilMode mode;
} formats[] =
{
{ "r8", GL_R8, tcu::Sampler::MODE_LAST },
{ "rg8_snorm", GL_RG8_SNORM, tcu::Sampler::MODE_LAST },
{ "rgb8", GL_RGB8, tcu::Sampler::MODE_LAST },
{ "rg32f", GL_RG32F, tcu::Sampler::MODE_LAST },
{ "r16i", GL_RG16I, tcu::Sampler::MODE_LAST },
{ "luminance", GL_LUMINANCE, tcu::Sampler::MODE_LAST },
{ "alpha", GL_ALPHA, tcu::Sampler::MODE_LAST },
{ "luminance_alpha", GL_LUMINANCE_ALPHA, tcu::Sampler::MODE_LAST },
{ "depth_component16", GL_DEPTH_COMPONENT16, tcu::Sampler::MODE_DEPTH },
{ "depth_component32f", GL_DEPTH_COMPONENT32F, tcu::Sampler::MODE_DEPTH },
{ "stencil_index8", GL_STENCIL_INDEX8, tcu::Sampler::MODE_STENCIL },
{ "depth32f_stencil8_sample_depth", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_DEPTH },
{ "depth32f_stencil8_sample_stencil", GL_DEPTH32F_STENCIL8, tcu::Sampler::MODE_STENCIL },
{ "depth24_stencil8_sample_depth", GL_DEPTH24_STENCIL8, tcu::Sampler::MODE_DEPTH },
{ "depth24_stencil8_sample_stencil", GL_DEPTH24_STENCIL8, tcu::Sampler::MODE_STENCIL },
{ "compressed_r11_eac", GL_COMPRESSED_R11_EAC, tcu::Sampler::MODE_LAST },
};
tcu::TestCaseGroup* const unusedGroup = new tcu::TestCaseGroup(m_testCtx, "unused_channels", "Tests channels that are not present in the internal format");
addChild(unusedGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
{
unusedGroup->addChild(new TextureBorderClampUnusedChannelCase(m_context,
formats[formatNdx].name,
"",
formats[formatNdx].format,
formats[formatNdx].mode));
}
}
}
} // Functional
} // gles31
} // deqp