/*------------------------------------------------------------------------- * 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 generateDummyCompressedData (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> genDummyTexture (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)); generateDummyCompressedData(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 = genDummyTexture<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 = genDummyTexture<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