blob: ddbc07c405b3871ca5548d250db041e86ae38ee4 [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES 3.1 Module
* -------------------------------------------------
*
* Copyright 2014 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 filtering tests.
*//*--------------------------------------------------------------------*/
#include "es31fTextureFilteringTests.hpp"
#include "glsTextureTestUtil.hpp"
#include "gluPixelTransfer.hpp"
#include "gluTexture.hpp"
#include "gluTextureUtil.hpp"
#include "tcuCommandLine.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "tcuVectorUtil.hpp"
#include "deStringUtil.hpp"
#include "deString.h"
#include "glwFunctions.hpp"
#include "glwEnums.hpp"
namespace deqp
{
namespace gles31
{
namespace Functional
{
using std::vector;
using std::string;
using tcu::TestLog;
using namespace gls::TextureTestUtil;
using namespace glu::TextureTestUtil;
static const char* getFaceDesc (const tcu::CubeFace face)
{
switch (face)
{
case tcu::CUBEFACE_NEGATIVE_X: return "-X";
case tcu::CUBEFACE_POSITIVE_X: return "+X";
case tcu::CUBEFACE_NEGATIVE_Y: return "-Y";
case tcu::CUBEFACE_POSITIVE_Y: return "+Y";
case tcu::CUBEFACE_NEGATIVE_Z: return "-Z";
case tcu::CUBEFACE_POSITIVE_Z: return "+Z";
default:
DE_ASSERT(false);
return DE_NULL;
}
}
static void logCubeArrayTexCoords(TestLog& log, vector<float>& texCoord)
{
const size_t numVerts = texCoord.size() / 4;
DE_ASSERT(texCoord.size() % 4 == 0);
for (size_t vertNdx = 0; vertNdx < numVerts; vertNdx++)
{
const size_t coordNdx = vertNdx * 4;
const float u = texCoord[coordNdx + 0];
const float v = texCoord[coordNdx + 1];
const float w = texCoord[coordNdx + 2];
const float q = texCoord[coordNdx + 3];
log << TestLog::Message
<< vertNdx << ": ("
<< u << ", "
<< v << ", "
<< w << ", "
<< q << ")"
<< TestLog::EndMessage;
}
}
// Cube map array filtering
class TextureCubeArrayFilteringCase : public TestCase
{
public:
TextureCubeArrayFilteringCase (Context& context,
const char* name,
const char* desc,
deUint32 minFilter,
deUint32 magFilter,
deUint32 wrapS,
deUint32 wrapT,
deUint32 internalFormat,
int size,
int depth,
bool onlySampleFaceInterior = false);
~TextureCubeArrayFilteringCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
private:
TextureCubeArrayFilteringCase (const TextureCubeArrayFilteringCase&);
TextureCubeArrayFilteringCase& operator= (const TextureCubeArrayFilteringCase&);
const deUint32 m_minFilter;
const deUint32 m_magFilter;
const deUint32 m_wrapS;
const deUint32 m_wrapT;
const deUint32 m_internalFormat;
const int m_size;
const int m_depth;
const bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
struct FilterCase
{
const glu::TextureCubeArray* texture;
tcu::Vec2 bottomLeft;
tcu::Vec2 topRight;
tcu::Vec2 layerRange;
FilterCase (void)
: texture(DE_NULL)
{
}
FilterCase (const glu::TextureCubeArray* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_, const tcu::Vec2& layerRange_)
: texture (tex_)
, bottomLeft (bottomLeft_)
, topRight (topRight_)
, layerRange (layerRange_)
{
}
};
glu::TextureCubeArray* m_gradientTex;
glu::TextureCubeArray* m_gridTex;
TextureRenderer m_renderer;
std::vector<FilterCase> m_cases;
int m_caseNdx;
};
TextureCubeArrayFilteringCase::TextureCubeArrayFilteringCase (Context& context,
const char* name,
const char* desc,
deUint32 minFilter,
deUint32 magFilter,
deUint32 wrapS,
deUint32 wrapT,
deUint32 internalFormat,
int size,
int depth,
bool onlySampleFaceInterior)
: TestCase (context, name, desc)
, m_minFilter (minFilter)
, m_magFilter (magFilter)
, m_wrapS (wrapS)
, m_wrapT (wrapT)
, m_internalFormat (internalFormat)
, m_size (size)
, m_depth (depth)
, m_onlySampleFaceInterior (onlySampleFaceInterior)
, m_gradientTex (DE_NULL)
, m_gridTex (DE_NULL)
, m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_310_ES, glu::PRECISION_HIGHP)
, m_caseNdx (0)
{
}
TextureCubeArrayFilteringCase::~TextureCubeArrayFilteringCase (void)
{
TextureCubeArrayFilteringCase::deinit();
}
void TextureCubeArrayFilteringCase::init (void)
{
auto ctxType = m_context.getRenderContext().getType();
const bool isES32orGL45 = glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
if (!isES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
if (m_internalFormat == GL_SR8_EXT && !(m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_R8")))
TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_R8 not supported");
if (m_internalFormat == GL_SRG8_EXT && !(m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_RG8")))
TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_RG8 not supported");
try
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat);
const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
const tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
const tcu::Vec4 cBias = fmtInfo.valueMin;
const int numLevels = deLog2Floor32(m_size) + 1;
const int numLayers = m_depth / 6;
if (!isContextTypeES(ctxType))
gl.enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
// Create textures.
m_gradientTex = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
m_gridTex = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
const tcu::IVec4 levelSwz[] =
{
tcu::IVec4(0,1,2,3),
tcu::IVec4(2,1,3,0),
tcu::IVec4(3,0,1,2),
tcu::IVec4(1,3,2,0),
};
// Fill first gradient texture (gradient direction varies between layers).
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
m_gradientTex->getRefTexture().allocLevel(levelNdx);
const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
{
const tcu::IVec4 swz = levelSwz[layerFaceNdx % DE_LENGTH_OF_ARRAY(levelSwz)];
const tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
const tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax);
}
}
// Fill second with grid texture (each layer has unique colors).
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
m_gridTex->getRefTexture().allocLevel(levelNdx);
const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
{
const deUint32 step = 0x00ffffff / (numLevels*m_depth - 1);
const deUint32 rgb = step * (levelNdx + layerFaceNdx*numLevels);
const deUint32 colorA = 0xff000000 | rgb;
const deUint32 colorB = 0xff000000 | ~rgb;
tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1),
4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
}
}
// Upload.
m_gradientTex->upload();
m_gridTex->upload();
// Test cases
{
const glu::TextureCubeArray* const tex0 = m_gradientTex;
const glu::TextureCubeArray* const tex1 = m_gridTex;
if (m_onlySampleFaceInterior)
{
m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); // minification
m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); // magnification
m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // minification
m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f, 0.5f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // magnification
}
else
{
const bool isSingleSample = (m_context.getRenderTarget().getNumSamples() == 0);
// minification - w/ tweak to avoid hitting triangle edges with a face switchpoint in multisample configs
if (isSingleSample)
m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
else
m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); // magnification
m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // minification
m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // magnification
// Layer rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
if (isSingleSample && (numLayers > 1))
m_cases.push_back(FilterCase(tex0, tcu::Vec2(-2.0f, -1.5f ), tcu::Vec2(-0.1f, 0.9f), tcu::Vec2(1.50001f, 1.49999f)));
}
}
m_caseNdx = 0;
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
catch (...)
{
// Clean up to save memory.
TextureCubeArrayFilteringCase::deinit();
throw;
}
}
void TextureCubeArrayFilteringCase::deinit (void)
{
delete m_gradientTex;
delete m_gridTex;
m_gradientTex = DE_NULL;
m_gridTex = DE_NULL;
m_renderer.clear();
m_cases.clear();
if (!isContextTypeES(m_context.getRenderContext().getType()))
m_context.getRenderContext().getFunctions().disable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}
TextureCubeArrayFilteringCase::IterateResult TextureCubeArrayFilteringCase::iterate (void)
{
TestLog& log = m_testCtx.getLog();
const glu::RenderContext& renderCtx = m_context.getRenderContext();
const glw::Functions& gl = renderCtx.getFunctions();
const int viewportSize = 28;
const deUint32 randomSeed = deStringHash(getName()) ^ deInt32Hash(m_caseNdx) ^ m_testCtx.getCommandLine().getBaseSeed();
const RandomViewport viewport (m_context.getRenderTarget(), viewportSize, viewportSize, randomSeed);
const FilterCase& curCase = m_cases[m_caseNdx];
const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat();
const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
ReferenceParams refParams (TEXTURETYPE_CUBE_ARRAY);
if (viewport.width < viewportSize || viewport.height < viewportSize)
throw tcu::NotSupportedError("Render target too small", "", __FILE__, __LINE__);
// Params for reference computation.
refParams.sampler = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
refParams.sampler.seamlessCubeMap = true;
refParams.samplerType = getSamplerType(texFmt);
refParams.colorBias = fmtInfo.lookupBias;
refParams.colorScale = fmtInfo.lookupScale;
refParams.lodMode = LODMODE_EXACT;
gl.bindTexture (GL_TEXTURE_CUBE_MAP_ARRAY, curCase.texture->getGLTexture());
gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter);
gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter);
gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS);
gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT);
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
{
const tcu::CubeFace face = tcu::CubeFace(faceNdx);
tcu::Surface result (viewport.width, viewport.height);
vector<float> texCoord;
computeQuadTexCoordCubeArray(texCoord, face, curCase.bottomLeft, curCase.topRight, curCase.layerRange);
log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
log << TestLog::Message << "Texture coordinates:" << TestLog::EndMessage;
logCubeArrayTexCoords(log, texCoord);
m_renderer.renderQuad(0, &texCoord[0], refParams);
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
glu::readPixels(renderCtx, viewport.x, viewport.y, result.getAccess());
GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
{
const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
const tcu::PixelFormat pixelFormat = renderCtx.getRenderTarget().getPixelFormat();
const tcu::IVec4 coordBits = tcu::IVec4(10);
const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
tcu::LodPrecision lodPrecision;
tcu::LookupPrecision lookupPrecision;
lodPrecision.derivateBits = 10;
lodPrecision.lodBits = 5;
lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
lookupPrecision.coordBits = coordBits.toWidth<3>();
lookupPrecision.uvwBits = tcu::IVec3(6);
lookupPrecision.colorMask = getCompareMask(pixelFormat);
const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
&texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
if (!isHighQuality)
{
// Evaluate against lower precision requirements.
lodPrecision.lodBits = 4;
lookupPrecision.uvwBits = tcu::IVec3(4);
m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
&texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
if (!isOk)
{
m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
}
else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
}
}
}
m_caseNdx += 1;
return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
}
TextureFilteringTests::TextureFilteringTests (Context& context)
: TestCaseGroup(context, "filtering", "Texture Filtering Tests")
{
}
TextureFilteringTests::~TextureFilteringTests (void)
{
}
void TextureFilteringTests::init (void)
{
static const struct
{
const char* name;
deUint32 mode;
} wrapModes[] =
{
{ "clamp", GL_CLAMP_TO_EDGE },
{ "repeat", GL_REPEAT },
{ "mirror", GL_MIRRORED_REPEAT }
};
static const struct
{
const char* name;
deUint32 mode;
} minFilterModes[] =
{
{ "nearest", GL_NEAREST },
{ "linear", GL_LINEAR },
{ "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST },
{ "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST },
{ "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR },
{ "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR }
};
static const struct
{
const char* name;
deUint32 mode;
} magFilterModes[] =
{
{ "nearest", GL_NEAREST },
{ "linear", GL_LINEAR }
};
static const struct
{
int size;
int depth;
} sizesCubeArray[] =
{
{ 8, 6 },
{ 64, 12 },
{ 128, 12 },
{ 7, 12 },
{ 63, 18 }
};
static const struct
{
const char* name;
deUint32 format;
} filterableFormatsByType[] =
{
{ "rgba16f", GL_RGBA16F },
{ "r11f_g11f_b10f", GL_R11F_G11F_B10F },
{ "rgb9_e5", GL_RGB9_E5 },
{ "rgba8", GL_RGBA8 },
{ "rgba8_snorm", GL_RGBA8_SNORM },
{ "rgb565", GL_RGB565 },
{ "rgba4", GL_RGBA4 },
{ "rgb5_a1", GL_RGB5_A1 },
{ "sr8", GL_SR8_EXT },
{ "srg8", GL_SRG8_EXT },
{ "srgb8_alpha8", GL_SRGB8_ALPHA8 },
{ "rgb10_a2", GL_RGB10_A2 }
};
// Cube map array texture filtering.
{
tcu::TestCaseGroup* const groupCubeArray = new tcu::TestCaseGroup(m_testCtx, "cube_array", "Cube Map Array Texture Filtering");
addChild(groupCubeArray);
// Formats.
{
tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "Cube Map Array Texture Formats");
groupCubeArray->addChild(formatsGroup);
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
{
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
{
const deUint32 minFilter = minFilterModes[filterNdx].mode;
const char* filterName = minFilterModes[filterNdx].name;
const deUint32 format = filterableFormatsByType[fmtNdx].format;
const char* formatName = filterableFormatsByType[fmtNdx].name;
const bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
const deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter;
const string name = string(formatName) + "_" + filterName;
const deUint32 wrapS = GL_REPEAT;
const deUint32 wrapT = GL_REPEAT;
const int size = 64;
const int depth = 12;
formatsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
name.c_str(), "",
minFilter, magFilter,
wrapS, wrapT,
format,
size, depth));
}
}
}
// Sizes.
{
tcu::TestCaseGroup* const sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
groupCubeArray->addChild(sizesGroup);
for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCubeArray); sizeNdx++)
{
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
{
const deUint32 minFilter = minFilterModes[filterNdx].mode;
const char* filterName = minFilterModes[filterNdx].name;
const deUint32 format = GL_RGBA8;
const bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
const deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter;
const deUint32 wrapS = GL_REPEAT;
const deUint32 wrapT = GL_REPEAT;
const int size = sizesCubeArray[sizeNdx].size;
const int depth = sizesCubeArray[sizeNdx].depth;
const string name = de::toString(size) + "x" + de::toString(size) + "x" + de::toString(depth) + "_" + filterName;
sizesGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
name.c_str(), "",
minFilter, magFilter,
wrapS, wrapT,
format,
size, depth));
}
}
}
// Wrap modes.
{
tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
groupCubeArray->addChild(combinationsGroup);
for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
{
for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
{
for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
{
for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
{
const deUint32 minFilter = minFilterModes[minFilterNdx].mode;
const deUint32 magFilter = magFilterModes[magFilterNdx].mode;
const deUint32 format = GL_RGBA8;
const deUint32 wrapS = wrapModes[wrapSNdx].mode;
const deUint32 wrapT = wrapModes[wrapTNdx].mode;
const int size = 63;
const int depth = 12;
const string name = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
combinationsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
name.c_str(), "",
minFilter, magFilter,
wrapS, wrapT,
format,
size, depth));
}
}
}
}
}
// Cases with no visible cube edges.
{
tcu::TestCaseGroup* const onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
groupCubeArray->addChild(onlyFaceInteriorGroup);
for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
{
const bool isLinear = isLinearI != 0;
const deUint32 filter = isLinear ? GL_LINEAR : GL_NEAREST;
onlyFaceInteriorGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
isLinear ? "linear" : "nearest", "",
filter, filter,
GL_REPEAT, GL_REPEAT,
GL_RGBA8,
63, 12,
true));
}
}
}
}
} // Functional
} // gles31
} // deqp