blob: 5b7e123ef514394665775e05d9390fd1b20c6646 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2017 The Khronos Group Inc.
*
* 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 es2cTexture3DTests.cpp
* \brief GL_OES_texture_3D tests definition.
*/ /*-------------------------------------------------------------------*/
#include "es2cTexture3DTests.hpp"
#include "deDefs.hpp"
#include "deInt32.h"
#include "deRandom.hpp"
#include "deString.h"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include "gluContextInfo.hpp"
#include "gluDrawUtil.hpp"
#include "gluPixelTransfer.hpp"
#include "gluShaderProgram.hpp"
#include "gluTexture.hpp"
#include "gluTextureTestUtil.hpp"
#include "gluTextureUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuImageCompare.hpp"
#include "tcuPixelFormat.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorUtil.hpp"
#include <map>
using namespace glw;
using namespace glu::TextureTestUtil;
namespace es2cts
{
enum
{
VIEWPORT_WIDTH = 64,
VIEWPORT_HEIGHT = 64,
};
typedef std::pair<int, const char*> CompressedFormatName;
static CompressedFormatName compressedFormatNames[] = {
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ETC1_RGB8, "etc1_rgb8_oes"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA, "rgba_astc_4x4_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA, "rgba_astc_5x4_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA, "rgba_astc_5x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA, "rgba_astc_6x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA, "rgba_astc_6x6_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA, "rgba_astc_8x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA, "rgba_astc_8x6_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA, "rgba_astc_8x8_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA, "rgba_astc_10x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA, "rgba_astc_10x6_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA, "rgba_astc_10x8_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA, "rgba_astc_10x10_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA, "rgba_astc_12x10_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA, "rgba_astc_12x12_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8, "srgb8_alpha8_astc_4x4_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8, "srgb8_alpha8_astc_5x4_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8, "srgb8_alpha8_astc_5x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8, "srgb8_alpha8_astc_6x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8, "srgb8_alpha8_astc_6x6_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8, "srgb8_alpha8_astc_8x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8, "srgb8_alpha8_astc_8x6_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8, "srgb8_alpha8_astc_8x8_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8, "sgb8_alpha8_astc_10x5_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8, "srgb8_alpha8_astc_10x6_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8, "srgb8_alpha8_astc_10x8_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8, "srgb8_alpha8_astc_10x10_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8, "srgb8_alpha8_astc_12x10_khr"),
CompressedFormatName(tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8, "srgb8_alpha8_astc_12x12_khr")
};
const char* getCompressedFormatName(tcu::CompressedTexFormat format)
{
static std::map<int, const char*> formatMap(compressedFormatNames,
compressedFormatNames + DE_LENGTH_OF_ARRAY(compressedFormatNames));
return formatMap.at(format);
}
class Texture3DBase : public deqp::TestCase
{
public:
Texture3DBase(deqp::Context& context, const char* name, const char* description);
virtual ~Texture3DBase(void);
bool isFeatureSupported() const;
void getSupportedCompressedFormats(std::set<int>& validFormats) const;
int calculateDataSize(deUint32 formats, int width, int height, int depth) const;
template <typename TextureType>
void verifyTestResult(const float* texCoords, const tcu::Surface& rendered, const TextureType& reference,
const ReferenceParams& refParams, bool isNearestOnly) const;
void uploadTexture3D(const glu::Texture3D& texture) const;
void renderQuad(glu::TextureTestUtil::TextureType textureType, const float* texCoords) const;
void verifyError(GLenum expectedError, const char* missmatchMessage) const;
void verifyError(GLenum expectedError1, GLenum expectedError2, const char* missmatchMessage) const;
// New methods wrappers.
void callTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type, const void* pixels) const;
void callTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) const;
void callCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x,
GLint y, GLsizei width, GLsizei height) const;
void callCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth, GLint border, GLsizei imageSize, const void* data) const;
void callCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize,
const void* data) const;
void callFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
GLint zoffset) const;
};
Texture3DBase::Texture3DBase(deqp::Context& context, const char* name, const char* description)
: deqp::TestCase(context, name, description)
{
}
Texture3DBase::~Texture3DBase(void)
{
}
bool Texture3DBase::isFeatureSupported() const
{
if (!m_context.getContextInfo().isExtensionSupported("GL_OES_texture_3D") &&
!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 0)) &&
!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 0)))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_texture_3D");
return false;
}
return true;
}
void Texture3DBase::getSupportedCompressedFormats(std::set<int>& formatsSet) const
{
const glu::ContextInfo& contextInfo = m_context.getContextInfo();
formatsSet.clear();
for (int formatNdx = 0; formatNdx < tcu::COMPRESSEDTEXFORMAT_LAST; formatNdx++)
{
// ETC2/EAC/BC (also known as DXT) texture compression algorithm
// supports only two-dimensional images
tcu::CompressedTexFormat format = static_cast<tcu::CompressedTexFormat>(formatNdx);
if (tcu::isEtcFormat(format) || tcu::isBcFormat(format))
continue;
int glFormat = glu::getGLFormat(format);
if (contextInfo.isCompressedTextureFormatSupported(glFormat))
formatsSet.insert(glFormat);
}
}
int Texture3DBase::calculateDataSize(deUint32 formats, int width, int height, int depth) const
{
tcu::CompressedTexFormat format = glu::mapGLCompressedTexFormat(formats);
const tcu::IVec3 blockPixelSize = tcu::getBlockPixelSize(format);
const int blockSize = tcu::getBlockSize(format);
return deDivRoundUp32(width, blockPixelSize.x()) * deDivRoundUp32(height, blockPixelSize.y()) *
deDivRoundUp32(depth, blockPixelSize.z()) * blockSize;
}
template <typename TextureType>
void Texture3DBase::verifyTestResult(const float* texCoords, const tcu::Surface& rendered, const TextureType& reference,
const ReferenceParams& refParams, bool isNearestOnly) const
{
const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
const tcu::IVec4 refChannelBitDepth = tcu::getTextureFormatBitDepth(reference.getFormat());
const tcu::IVec4 colorBits = max(tcu::IVec4(de::min(pixelFormat.redBits, refChannelBitDepth[0]),
de::min(pixelFormat.greenBits, refChannelBitDepth[1]),
de::min(pixelFormat.blueBits, refChannelBitDepth[2]),
de::min(pixelFormat.alphaBits, refChannelBitDepth[3])) - (isNearestOnly ? 1 : 2),
tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
tcu::LodPrecision lodPrecision(18, 6);
tcu::LookupPrecision lookupPrecision;
lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
lookupPrecision.coordBits = tcu::IVec3(20, 20, 20);
lookupPrecision.uvwBits = tcu::IVec3(7, 7, 7);
lookupPrecision.colorMask = getCompareMask(pixelFormat);
if (verifyTextureResult(m_testCtx, rendered.getAccess(), reference, texCoords, refParams, lookupPrecision,
lodPrecision, pixelFormat))
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return;
}
// Evaluate against lower precision requirements.
lodPrecision.lodBits = 4;
lookupPrecision.uvwBits = tcu::IVec3(4, 4, 4);
tcu::TestLog& log = m_testCtx.getLog();
log << tcu::TestLog::Message
<< "Warning: Verification against high precision requirements failed, trying with lower requirements."
<< tcu::TestLog::EndMessage;
if (verifyTextureResult(m_testCtx, rendered.getAccess(), reference, texCoords, refParams, lookupPrecision,
lodPrecision, pixelFormat))
{
m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
return;
}
log << tcu::TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
}
void Texture3DBase::uploadTexture3D(const glu::Texture3D& texture) const
{
// note: this function is modified version of glu::Texture3D::upload()
// this was needed to support methods added by GL_OES_texture_3D extension
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
deUint32 textureName = texture.getGLTexture();
const tcu::Texture3D& referenceTexture = texture.getRefTexture();
TCU_CHECK(textureName);
gl.bindTexture(GL_TEXTURE_3D, textureName);
GLint pixelStorageMode = 1;
int pixelSize = referenceTexture.getFormat().getPixelSize();
if (deIsPowerOfTwo32(pixelSize))
pixelStorageMode = de::min(pixelSize, 8);
gl.pixelStorei(GL_UNPACK_ALIGNMENT, pixelStorageMode);
GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed");
glu::TransferFormat transferFormat = glu::getTransferFormat(referenceTexture.getFormat());
for (int levelNdx = 0; levelNdx < referenceTexture.getNumLevels(); levelNdx++)
{
if (referenceTexture.isLevelEmpty(levelNdx))
continue; // Don't upload.
tcu::ConstPixelBufferAccess access = referenceTexture.getLevel(levelNdx);
DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth());
DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize() * access.getWidth() * access.getHeight());
callTexImage3D(GL_TEXTURE_3D, levelNdx, transferFormat.format, access.getWidth(), access.getHeight(),
access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType,
access.getDataPtr());
}
GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed");
}
void Texture3DBase::renderQuad(glu::TextureTestUtil::TextureType textureType, const float* texCoords) const
{
glu::RenderContext& renderContext = m_context.getRenderContext();
glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(renderContext.getType());
const glw::Functions& gl = renderContext.getFunctions();
// Prepare data for rendering
static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
static const float position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };
static const char* vsTemplate = "${VERSION}\n"
"attribute highp vec4 a_position;\n"
"attribute highp ${TEXCOORD_TYPE} a_texCoord;\n"
"varying highp ${TEXCOORD_TYPE} v_texCoord;\n"
"void main (void) {\n"
" gl_Position = a_position;\n"
" v_texCoord = a_texCoord;\n"
"}\n";
static const char* fsTemplate = "${VERSION}\n"
"${HEADER}\n"
"varying highp ${TEXCOORD_TYPE} v_texCoord;\n"
"uniform highp ${SAMPLER_TYPE} u_sampler;\n"
"void main (void) {\n"
" gl_FragColor = ${LOOKUP}(u_sampler, v_texCoord);\n"
"}\n";
int numComponents = 3;
std::map<std::string, std::string> specializationMap;
specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
if (textureType == TEXTURETYPE_3D)
{
specializationMap["HEADER"] = "#extension GL_OES_texture_3D : enable";
specializationMap["TEXCOORD_TYPE"] = "vec3";
specializationMap["SAMPLER_TYPE"] = "sampler3D";
specializationMap["LOOKUP"] = "texture3D";
}
else if (textureType == TEXTURETYPE_2D)
{
numComponents = 2;
specializationMap["HEADER"] = "";
specializationMap["TEXCOORD_TYPE"] = "vec2";
specializationMap["SAMPLER_TYPE"] = "sampler2D";
specializationMap["LOOKUP"] = "texture2D";
}
else
TCU_FAIL("Unsuported texture type.");
// Specialize shaders
std::string vs = tcu::StringTemplate(vsTemplate).specialize(specializationMap);
std::string fs = tcu::StringTemplate(fsTemplate).specialize(specializationMap);
glu::ProgramSources programSources(glu::makeVtxFragSources(vs, fs));
// Create program
glu::ShaderProgram testProgram(renderContext, programSources);
if (!testProgram.isOk())
{
m_testCtx.getLog() << testProgram;
TCU_FAIL("Compile failed");
}
// Set uniforms
deUint32 programId = testProgram.getProgram();
gl.useProgram(programId);
gl.uniform1i(gl.getUniformLocation(programId, "u_sampler"), 0);
// Define vertex attributes
const glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("a_position", 2, 4, 0, position),
glu::va::Float("a_texCoord", numComponents, 4, 0, texCoords) };
// Draw quad
glu::draw(m_context.getRenderContext(), programId, DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices));
}
void Texture3DBase::verifyError(GLenum expectedError, const char* missmatchMessage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLenum currentError = gl.getError();
if (currentError == expectedError)
return;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect error was reported");
m_testCtx.getLog() << tcu::TestLog::Message << glu::getErrorStr(static_cast<int>(expectedError))
<< " was expected but got " << glu::getErrorStr(static_cast<int>(currentError)) << ". "
<< missmatchMessage << tcu::TestLog::EndMessage;
}
void Texture3DBase::verifyError(GLenum expectedError1, GLenum expectedError2, const char* missmatchMessage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLenum currentError = gl.getError();
if ((currentError == expectedError1) || (currentError == expectedError2))
return;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect error was reported");
m_testCtx.getLog() << tcu::TestLog::Message << glu::getErrorStr(static_cast<int>(expectedError1)) << " or "
<< glu::getErrorStr(static_cast<int>(expectedError1)) << " was expected but got "
<< glu::getErrorStr(static_cast<int>(currentError)) << ". " << missmatchMessage
<< tcu::TestLog::EndMessage;
}
void Texture3DBase::callTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height,
GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (gl.texImage3DOES)
gl.texImage3DOES(target, level, internalFormat, width, height, depth, border, format, type, pixels);
else if (gl.texImage3D)
gl.texImage3D(target, level, static_cast<GLint>(internalFormat), width, height, depth, border, format, type,
pixels);
else
TCU_FAIL("glTexImage3D not supported");
}
void Texture3DBase::callTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
const void* pixels) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (gl.texSubImage3DOES)
gl.texSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
else if (gl.texSubImage3D)
gl.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
else
TCU_FAIL("glTexSubImage3D not supported");
}
void Texture3DBase::callCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLint x, GLint y, GLsizei width, GLsizei height) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (gl.copyTexSubImage3DOES)
gl.copyTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, x, y, width, height);
else if (gl.copyTexSubImage3D)
gl.copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
else
TCU_FAIL("glCopyTexSubImage3D not supported");
}
void Texture3DBase::callCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
GLsizei height, GLsizei depth, GLint border, GLsizei imageSize,
const void* data) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (gl.compressedTexImage3DOES)
gl.compressedTexImage3DOES(target, level, internalformat, width, height, depth, border, imageSize, data);
else if (gl.compressedTexImage3D)
gl.compressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data);
else
TCU_FAIL("gl.compressedTexImage3D not supported");
}
void Texture3DBase::callCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format,
GLsizei imageSize, const void* data) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (gl.compressedTexSubImage3DOES)
gl.compressedTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize,
data);
else if (gl.compressedTexSubImage3D)
gl.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize,
data);
else
TCU_FAIL("gl.compressedTexSubImage3D not supported");
}
void Texture3DBase::callFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
GLint level, GLint zoffset) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (gl.framebufferTexture3DOES)
gl.framebufferTexture3DOES(target, attachment, textarget, texture, level, zoffset);
else if (gl.framebufferTexture3D)
gl.framebufferTexture3D(target, attachment, textarget, texture, level, zoffset);
else
TCU_FAIL("glFramebufferTexture3D not supported");
}
struct FilteringData
{
GLint minFilter;
GLint magFilter;
GLint wrapS;
GLint wrapT;
GLint wrapR;
deUint32 internalFormat;
int width;
int height;
int depth;
};
class Texture3DFilteringCase : public Texture3DBase
{
public:
Texture3DFilteringCase(deqp::Context& context, const char* name, const char* desc, const FilteringData& data);
~Texture3DFilteringCase(void);
void init(void);
void deinit(void);
IterateResult iterate(void);
private:
struct FilterCase
{
const glu::Texture3D* texture;
tcu::Vec3 lod;
tcu::Vec3 offset;
FilterCase(void) : texture(DE_NULL)
{
}
FilterCase(const glu::Texture3D* tex_, const tcu::Vec3& lod_, const tcu::Vec3& offset_)
: texture(tex_), lod(lod_), offset(offset_)
{
}
};
private:
Texture3DFilteringCase(const Texture3DFilteringCase& other);
Texture3DFilteringCase& operator=(const Texture3DFilteringCase& other);
const FilteringData m_filteringData;
glu::Texture3D* m_gradientTex;
glu::Texture3D* m_gridTex;
std::vector<FilterCase> m_cases;
int m_caseNdx;
};
Texture3DFilteringCase::Texture3DFilteringCase(deqp::Context& context, const char* name, const char* desc,
const FilteringData& data)
: Texture3DBase(context, name, desc)
, m_filteringData(data)
, m_gradientTex(DE_NULL)
, m_gridTex(DE_NULL)
, m_caseNdx(0)
{
}
Texture3DFilteringCase::~Texture3DFilteringCase(void)
{
Texture3DFilteringCase::deinit();
}
void Texture3DFilteringCase::init(void)
{
if (!isFeatureSupported())
return;
const deUint32 internalFormat = m_filteringData.internalFormat;
const int width = m_filteringData.width;
const int height = m_filteringData.height;
const int depth = m_filteringData.depth;
const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(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(de::max(de::max(width, height), depth)) + 1;
// Create textures.
m_gradientTex = new glu::Texture3D(m_context.getRenderContext(), internalFormat, width, height, depth);
m_gridTex = new glu::Texture3D(m_context.getRenderContext(), internalFormat, width, height, depth);
// Fill first gradient texture.
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
m_gradientTex->getRefTexture().allocLevel(levelNdx);
tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
}
// Fill second with grid texture.
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
deUint32 step = 0x00ffffff / numLevels;
deUint32 rgb = step * levelNdx;
deUint32 colorA = 0xff000000 | rgb;
deUint32 colorB = 0xff000000 | ~rgb;
m_gridTex->getRefTexture().allocLevel(levelNdx);
tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec() * cScale + cBias,
tcu::RGBA(colorB).toVec() * cScale + cBias);
}
// Upload.
uploadTexture3D(*m_gradientTex);
uploadTexture3D(*m_gridTex);
// Test cases
m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec3(1.5f, 2.8f, 1.0f), tcu::Vec3(-1.0f, -2.7f, -2.275f)));
m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec3(-2.0f, -1.5f, -1.8f), tcu::Vec3(-0.1f, 0.9f, -0.25f)));
m_cases.push_back(FilterCase(m_gridTex, tcu::Vec3(0.2f, 0.175f, 0.3f), tcu::Vec3(-2.0f, -3.7f, -1.825f)));
m_cases.push_back(FilterCase(m_gridTex, tcu::Vec3(-0.8f, -2.3f, -2.5f), tcu::Vec3(0.2f, -0.1f, 1.325f)));
m_caseNdx = 0;
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
void Texture3DFilteringCase::deinit(void)
{
delete m_gradientTex;
delete m_gridTex;
m_gradientTex = DE_NULL;
m_gridTex = DE_NULL;
m_cases.clear();
}
Texture3DFilteringCase::IterateResult Texture3DFilteringCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
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(), std::string("Test") + de::toString(m_caseNdx),
std::string("Test ") + de::toString(m_caseNdx));
tcu::TestLog& log = m_testCtx.getLog();
ReferenceParams refParams(TEXTURETYPE_3D);
tcu::Surface rendered(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
tcu::Vec3 texCoord[4];
// Setup params for reference.
refParams.sampler = glu::mapGLSampler(m_filteringData.wrapS, m_filteringData.wrapT, m_filteringData.wrapR,
m_filteringData.minFilter, m_filteringData.magFilter);
refParams.samplerType = getSamplerType(texFmt);
refParams.lodMode = LODMODE_EXACT;
refParams.colorBias = fmtInfo.lookupBias;
refParams.colorScale = fmtInfo.lookupScale;
// Compute texture coordinates.
log << tcu::TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset
<< tcu::TestLog::EndMessage;
{
const float lodX = curCase.lod.x();
const float lodY = curCase.lod.y();
const float lodZ = curCase.lod.z();
const float oX = curCase.offset.x();
const float oY = curCase.offset.y();
const float oZ = curCase.offset.z();
const float sX = deFloatExp2(lodX) * float(VIEWPORT_WIDTH) / float(m_gradientTex->getRefTexture().getWidth());
const float sY = deFloatExp2(lodY) * float(VIEWPORT_HEIGHT) / float(m_gradientTex->getRefTexture().getHeight());
const float sZ = deFloatExp2(lodZ) * float(VIEWPORT_WIDTH) / float(m_gradientTex->getRefTexture().getDepth());
texCoord[0] = tcu::Vec3(oX, oY, oZ);
texCoord[1] = tcu::Vec3(oX, oY + sY, oZ + sZ * 0.5f);
texCoord[2] = tcu::Vec3(oX + sX, oY, oZ + sZ * 0.5f);
texCoord[3] = tcu::Vec3(oX + sX, oY + sY, oZ + sZ);
}
gl.bindTexture(GL_TEXTURE_3D, curCase.texture->getGLTexture());
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, m_filteringData.minFilter);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, m_filteringData.magFilter);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, m_filteringData.wrapS);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, m_filteringData.wrapT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, m_filteringData.wrapR);
// Verify bound 3D texture.
GLint resultName;
gl.getIntegerv(GL_TEXTURE_BINDING_3D, &resultName);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
if (curCase.texture->getGLTexture() == static_cast<deUint32>(resultName))
{
// Render.
gl.viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
renderQuad(TEXTURETYPE_3D, texCoord->getPtr());
glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess());
// Compare rendered image to reference.
const bool isNearestOnly =
(m_filteringData.minFilter == GL_NEAREST) && (m_filteringData.magFilter == GL_NEAREST);
verifyTestResult(texCoord[0].getPtr(), rendered, curCase.texture->getRefTexture(), refParams, isNearestOnly);
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid texture name");
}
++m_caseNdx;
return (m_caseNdx < static_cast<int>(m_cases.size())) ? CONTINUE : STOP;
}
class TexSubImage3DCase : public Texture3DBase
{
public:
TexSubImage3DCase(deqp::Context& context, const char* name, const char* desc, deUint32 internalFormat, int width,
int height, int depth);
IterateResult iterate(void);
private:
deUint32 m_internalFormat;
int m_width;
int m_height;
int m_depth;
int m_numLevels;
};
TexSubImage3DCase::TexSubImage3DCase(deqp::Context& context, const char* name, const char* desc,
deUint32 internalFormat, int width, int height, int depth)
: Texture3DBase(context, name, desc)
, m_internalFormat(internalFormat)
, m_width(width)
, m_height(height)
, m_depth(depth)
, m_numLevels(static_cast<int>(deLog2Floor32(de::max(width, de::max(height, depth))) + 1))
{
}
TexSubImage3DCase::IterateResult TexSubImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
glu::RenderContext& renderCtx = m_context.getRenderContext();
const glw::Functions& gl = renderCtx.getFunctions();
tcu::Vec4 firstColor(0.0f, 1.0f, 0.0f, 1.0f);
tcu::Vec4 secondColor(1.0f, 0.0f, 1.0f, 1.0f);
glu::Texture3D texture(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
const tcu::TextureFormat textureFormat = texture.getRefTexture().getFormat();
const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(textureFormat);
// Fill texture.
for (int levelNdx = 0; levelNdx < m_numLevels; levelNdx++)
{
texture.getRefTexture().allocLevel(levelNdx);
const tcu::PixelBufferAccess& pba = texture.getRefTexture().getLevel(levelNdx);
tcu::fillWithComponentGradients(pba, firstColor, secondColor);
}
// Upload texture
uploadTexture3D(texture);
gl.bindTexture(GL_TEXTURE_3D, texture.getGLTexture());
GLU_EXPECT_NO_ERROR(gl.getError(), "gl.bindTexture");
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri for GL_TEXTURE_WRAP_R");
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri for GL_TEXTURE_WRAP_T");
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri for GL_TEXTURE_WRAP_R");
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri for GL_TEXTURE_MIN_FILTER");
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri for GL_TEXTURE_MAG_FILTER");
// Re-specify parts of each level in uploaded texture and in reference texture
tcu::TextureLevel data(textureFormat);
for (int levelNdx = 0; levelNdx < m_numLevels - 2; levelNdx++)
{
int scale = levelNdx + 1;
int w = de::max(1, m_width >> scale);
int h = de::max(1, m_height >> scale);
int d = de::max(1, m_depth >> levelNdx);
data.setSize(w, h, d);
tcu::clear(data.getAccess(), secondColor);
glu::TransferFormat transferFormat = glu::getTransferFormat(textureFormat);
callTexSubImage3D(GL_TEXTURE_3D, levelNdx, w, h, 0, w, h, d, transferFormat.format, transferFormat.dataType,
data.getAccess().getDataPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage3D");
const tcu::PixelBufferAccess& pba = texture.getRefTexture().getLevel(levelNdx);
tcu::clear(getSubregion(pba, w, h, 0, w, h, d), secondColor);
}
// Setup params for reference.
ReferenceParams refParams(TEXTURETYPE_3D);
refParams.sampler = glu::mapGLSampler(GL_REPEAT, GL_REPEAT, GL_REPEAT, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST);
refParams.samplerType = getSamplerType(textureFormat);
refParams.lodMode = LODMODE_EXACT;
refParams.colorBias = formatInfo.lookupBias;
refParams.colorScale = formatInfo.lookupScale;
tcu::Vec3 texCoord[4] = { tcu::Vec3(0.0f, 0.0f, 0.5f), tcu::Vec3(0.0f, 1.0f, 0.5f), tcu::Vec3(1.0f, 0.0f, 0.5f),
tcu::Vec3(1.0f, 1.0f, 0.5f) };
// Render.
gl.viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
renderQuad(TEXTURETYPE_3D, texCoord[0].getPtr());
tcu::Surface rendered(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess());
// Compare rendered image to reference.
verifyTestResult(texCoord[0].getPtr(), rendered, texture.getRefTexture(), refParams, false);
return STOP;
}
class CopyTexSubImage3DCase : public Texture3DBase
{
public:
CopyTexSubImage3DCase(deqp::Context& context, const char* name, const char* desc, deUint32 format,
deUint32 type, int width, int height, int depth);
IterateResult iterate(void);
private:
deUint32 m_format;
deUint32 m_type;
int m_width;
int m_height;
int m_depth;
int m_numLevels;
};
CopyTexSubImage3DCase::CopyTexSubImage3DCase(deqp::Context& context, const char* name, const char* desc,
deUint32 format, deUint32 type, int width, int height, int depth)
: Texture3DBase(context, name, desc)
, m_format(format)
, m_type(type)
, m_width(width)
, m_height(height)
, m_depth(depth)
, m_numLevels(static_cast<int>(deLog2Floor32(de::max(width, de::max(height, depth))) + 1))
{
}
CopyTexSubImage3DCase::IterateResult CopyTexSubImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
glu::RenderContext& renderCtx = m_context.getRenderContext();
const glw::Functions& gl = renderCtx.getFunctions();
ReferenceParams refParams(TEXTURETYPE_3D);
tcu::Surface rendered(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
tcu::Vec4 firstColor(0.0f, 1.0f, 0.0f, 1.0f);
tcu::Vec4 secondColor(1.0f, 0.0f, 1.0f, 1.0f);
glu::Texture3D texture(m_context.getRenderContext(), m_format, m_type, m_width, m_height, m_depth);
const tcu::TextureFormat textureFormat = texture.getRefTexture().getFormat();
const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(textureFormat);
glw::GLuint fbo = 0;
gl.genFramebuffers(1, &fbo);
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
glw::GLuint new_dst_to = 0;
gl.genTextures(1, &new_dst_to);
gl.bindTexture(GL_TEXTURE_2D, new_dst_to);
/* The longest edge of texture(32*64*8) is 64, so we create a texture with 64*64 dimension. */
gl.texImage2D(GL_TEXTURE_2D, 0, m_format, 64, 64, 0, m_format, m_type, NULL);
GLU_EXPECT_NO_ERROR(gl.getError(),
"Could not setup texture object for draw framebuffer color attachment.");
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, new_dst_to, 0);
GLU_EXPECT_NO_ERROR(gl.getError(),
"Could not attach texture object to draw framebuffer color attachment.");
// Fill texture.
for (int levelNdx = 0; levelNdx < m_numLevels; levelNdx++)
{
texture.getRefTexture().allocLevel(levelNdx);
const tcu::PixelBufferAccess& pba = texture.getRefTexture().getLevel(levelNdx);
tcu::fillWithComponentGradients(pba, firstColor, secondColor);
}
// Upload texture.
uploadTexture3D(texture);
gl.clearColor(secondColor[0], secondColor[1], secondColor[2], secondColor[3]);
gl.clear(GL_COLOR_BUFFER_BIT);
gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
gl.bindTexture(GL_TEXTURE_3D, texture.getGLTexture());
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Re-specify parts of each level in uploaded texture and in reference texture
tcu::TextureLevel data(textureFormat);
for (int levelNdx = 0; levelNdx < m_numLevels - 2; levelNdx++)
{
int scale = levelNdx + 1;
int w = de::max(1, m_width >> scale);
int h = de::max(1, m_height >> scale);
int d = de::max(1, m_depth >> levelNdx);
data.setSize(w, h, d);
tcu::clear(data.getAccess(), secondColor);
for (int depthNdx = 0; depthNdx < d; depthNdx++)
{
callCopyTexSubImage3D(GL_TEXTURE_3D, levelNdx, w, h, depthNdx, 0, 0, w, h);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCopyTexSubImage3D");
}
const tcu::PixelBufferAccess& pba = texture.getRefTexture().getLevel(levelNdx);
tcu::clear(getSubregion(pba, w, h, 0, w, h, d), secondColor);
}
// Setup params for reference.
refParams.sampler = glu::mapGLSampler(GL_REPEAT, GL_REPEAT, GL_REPEAT, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST);
refParams.samplerType = getSamplerType(textureFormat);
refParams.lodMode = LODMODE_EXACT;
refParams.colorBias = formatInfo.lookupBias;
refParams.colorScale = formatInfo.lookupScale;
tcu::Vec3 texCoord[4] = { tcu::Vec3(0.0f, 0.0f, 0.5f), tcu::Vec3(0.0f, 1.0f, 0.5f), tcu::Vec3(1.0f, 0.0f, 0.5f),
tcu::Vec3(1.0f, 1.0f, 0.5f) };
// Render.
gl.viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
renderQuad(TEXTURETYPE_3D, texCoord[0].getPtr());
glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess());
// Compare rendered image to reference.
verifyTestResult(texCoord[0].getPtr(), rendered, texture.getRefTexture(), refParams, false);
gl.deleteTextures(1, &new_dst_to);
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
gl.deleteFramebuffers(1, &fbo);
return STOP;
}
class FramebufferTexture3DCase : public Texture3DBase
{
public:
FramebufferTexture3DCase(deqp::Context& context, const char* name, const char* desc, deUint32 format,
deUint32 type, int width, int height, int depth);
IterateResult iterate(void);
private:
deUint32 m_format;
deUint32 m_type;
int m_width;
int m_height;
int m_depth;
int m_numLevels;
};
FramebufferTexture3DCase::FramebufferTexture3DCase(deqp::Context& context, const char* name, const char* desc,
deUint32 format, deUint32 type, int width, int height, int depth)
: Texture3DBase(context, name, desc)
, m_format(format)
, m_type(type)
, m_width(width)
, m_height(height)
, m_depth(depth)
, m_numLevels(static_cast<int>(deLog2Floor32(de::max(width, de::max(height, depth))) + 1))
{
}
FramebufferTexture3DCase::IterateResult FramebufferTexture3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
glu::RenderContext& renderCtx = m_context.getRenderContext();
const glw::Functions& gl = renderCtx.getFunctions();
tcu::Vec4 firstColor(0.0f, 1.0f, 0.0f, 1.0f);
tcu::Vec4 secondColor(1.0f, 0.0f, 1.0f, 1.0f);
glu::Texture3D texture3D(m_context.getRenderContext(), m_format, m_type, m_width, m_height, m_depth);
glu::Texture2D texture2D(m_context.getRenderContext(), m_format, m_type, m_width, m_height);
// Fill textures.
texture3D.getRefTexture().allocLevel(0);
const tcu::PixelBufferAccess& pba3D = texture3D.getRefTexture().getLevel(0);
tcu::clear(pba3D, secondColor);
for (int levelNdx = 0; levelNdx < m_numLevels; levelNdx++)
{
texture2D.getRefTexture().allocLevel(levelNdx);
const tcu::PixelBufferAccess& pba2D = texture2D.getRefTexture().getLevel(levelNdx);
tcu::fillWithGrid(pba2D, 4, firstColor, secondColor);
}
// Upload textures.
uploadTexture3D(texture3D);
texture2D.upload();
gl.bindTexture(GL_TEXTURE_3D, texture3D.getGLTexture());
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Create framebuffer.
glw::GLuint fbo = 0;
gl.genFramebuffers(1, &fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers");
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers");
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture3D.getGLTexture(), 0, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture3D");
deUint32 status = gl.checkFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
TCU_FAIL("Framebuffer is not complete");
gl.bindTexture(GL_TEXTURE_2D, texture2D.getGLTexture());
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_MIPMAP_NEAREST);
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const tcu::TextureFormat textureFormat = texture2D.getRefTexture().getFormat();
const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(textureFormat);
tcu::Vec2 texCoord[4] = { tcu::Vec2(0.0f, 0.0f), tcu::Vec2(0.0f, 1.0f), tcu::Vec2(1.0f, 0.0f),
tcu::Vec2(1.0f, 1.0f) };
// Render to fbo.
gl.viewport(0, 0, m_width, m_height);
renderQuad(TEXTURETYPE_2D, texCoord[0].getPtr());
// Setup params for reference.
ReferenceParams refParams(TEXTURETYPE_2D);
refParams.sampler = glu::mapGLSampler(GL_REPEAT, GL_REPEAT, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST);
refParams.samplerType = getSamplerType(textureFormat);
refParams.lodMode = LODMODE_EXACT;
refParams.colorBias = formatInfo.lookupBias;
refParams.colorScale = formatInfo.lookupScale;
// Compare image rendered to selected layer of 3d texture to reference.
tcu::Surface rendered(m_width, m_height);
glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess());
verifyTestResult(texCoord[0].getPtr(), rendered, texture2D.getRefTexture(), refParams, false);
// Cleanup.
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
gl.deleteFramebuffers(1, &fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers");
return STOP;
}
class CompressedTexture3DCase : public Texture3DBase
{
public:
CompressedTexture3DCase(deqp::Context& context, const char* name, deUint32 format);
IterateResult iterate(void);
private:
int m_compressedFormat;
};
CompressedTexture3DCase::CompressedTexture3DCase(deqp::Context& context, const char* name, deUint32 format)
: Texture3DBase(context, name, ""), m_compressedFormat(static_cast<int>(format))
{
}
CompressedTexture3DCase::IterateResult CompressedTexture3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glu::ContextInfo& contextInfo = m_context.getContextInfo();
tcu::CompressedTexFormat format = glu::mapGLCompressedTexFormat(m_compressedFormat);
if (!contextInfo.isCompressedTextureFormatSupported(m_compressedFormat))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Compressed format not supported by implementation");
return STOP;
}
const deInt32 width = 64;
const deInt32 height = 64;
const deInt32 depth = 4;
const deInt32 levelsCount = 4;
GLuint textureName;
gl.genTextures(1, &textureName);
GLU_EXPECT_NO_ERROR(gl.getError(), "gl.genTextures");
gl.bindTexture(GL_TEXTURE_3D, textureName);
GLU_EXPECT_NO_ERROR(gl.getError(), "gl.bindTexture");
// Create 3D texture with random data.
for (deInt32 levelIndex = 0; levelIndex < levelsCount; ++levelIndex)
{
deInt32 levelWidth = de::max(width >> levelIndex, 1);
deInt32 levelHeight = de::max(height >> levelIndex, 1);
deInt32 levelDepth = de::max(depth >> levelIndex, 1);
tcu::CompressedTexture level(format, levelWidth, levelHeight, levelDepth);
const int dataSize = level.getDataSize();
deUint8* const data = static_cast<deUint8*>(level.getData());
de::Random rnd(deStringHash(getName()) + levelIndex);
for (int i = 0; i < dataSize; i++)
data[i] = rnd.getUint32() & 0xff;
callCompressedTexImage3D(GL_TEXTURE_3D, levelIndex, m_compressedFormat, level.getWidth(), level.getHeight(),
level.getDepth(), 0 /* border */, level.getDataSize(), level.getData());
GLU_EXPECT_NO_ERROR(gl.getError(), "callCompressedTexImage3D");
}
// Replace whole texture data.
for (deInt32 levelIndex = levelsCount - 2; levelIndex >= 0; --levelIndex)
{
deInt32 partWidth = de::max(width >> levelIndex, 1);
deInt32 partHeight = de::max(height >> levelIndex, 1);
deInt32 partDepth = de::max(depth >> levelIndex, 1);
;
tcu::CompressedTexture dataPart(format, partWidth, partHeight, partDepth);
const int dataSize = dataPart.getDataSize();
deUint8* const data = static_cast<deUint8*>(dataPart.getData());
de::Random rnd(deStringHash(getName()) + levelIndex);
for (int i = 0; i < dataSize; i++)
data[i] = rnd.getUint32() & 0xff;
callCompressedTexSubImage3D(GL_TEXTURE_3D, levelIndex, 0, 0, 0, dataPart.getWidth(), dataPart.getHeight(),
dataPart.getDepth(), m_compressedFormat, dataPart.getDataSize(),
dataPart.getData());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexSubImage3D");
}
gl.deleteTextures(1, &textureName);
GLU_EXPECT_NO_ERROR(gl.getError(), "gl.deleteTextures");
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
class NegativeTexImage3DCase : public Texture3DBase
{
public:
NegativeTexImage3DCase(deqp::Context& context, const char* name);
IterateResult iterate(void);
};
NegativeTexImage3DCase::NegativeTexImage3DCase(deqp::Context& context, const char* name)
: Texture3DBase(context, name, "")
{
}
NegativeTexImage3DCase::IterateResult NegativeTexImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// negative usage
{
const char* message1 = "GL_INVALID_ENUM is generated if target is invalid.";
callTexImage3D(0, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_ENUM, message1);
callTexImage3D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_ENUM, message1);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, 0, 0);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if type is not a type constant.");
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0, 0, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if format is not an accepted format constant.");
callTexImage3D(GL_TEXTURE_3D, 0, 0, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if internalFormat is not one of the accepted "
"resolution and format symbolic constants.");
const char* message2 = "GL_INVALID_OPERATION is generated if target is GL_TEXTURE_3D and format is "
"GL_DEPTH_COMPONENT, or GL_DEPTH_STENCIL.";
callTexImage3D(GL_TEXTURE_3D, 0, GL_DEPTH_STENCIL, 1, 1, 1, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
verifyError(GL_INVALID_OPERATION, message2);
callTexImage3D(GL_TEXTURE_3D, 0, GL_DEPTH_COMPONENT, 1, 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_OPERATION, message2);
const char* message3 =
"GL_INVALID_OPERATION is generated if the combination of internalFormat, format and type is invalid.";
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_OPERATION, message3);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_4_4_4_4, 0);
verifyError(GL_INVALID_OPERATION, message3);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGB5_A1, 1, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, 0);
verifyError(GL_INVALID_OPERATION, message3);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGB10_A2, 1, 1, 1, 0, GL_RGB, GL_UNSIGNED_INT_2_10_10_10_REV, 0);
verifyError(GL_INVALID_OPERATION, message3);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32UI, 1, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, 0);
verifyError(GL_INVALID_OPERATION, message3);
}
// invalid leve
{
const char* message = "GL_INVALID_VALUE is generated if level is less than 0.";
callTexImage3D(GL_TEXTURE_3D, -1, GL_RGB, 1, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
}
// maximal level
{
int max3DTexSize;
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTexSize);
GLint log2Max3DTextureSize = deLog2Floor32(max3DTexSize) + 1;
callTexImage3D(GL_TEXTURE_3D, log2Max3DTextureSize, GL_RGB, 1, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE,
"GL_INVALID_VALUE is generated if level is greater than log_2(GL_MAX_3D_TEXTURE_SIZE).");
}
// negative dimensions
{
const char* message = "GL_INVALID_VALUE is generated if width or height is less than 0.";
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, -1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, -1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, -1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, -1, -1, -1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
}
// maximal dimensions
{
int aboveMax3DTextureSize;
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &aboveMax3DTextureSize);
int aboveMaxTextureSize;
gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &aboveMaxTextureSize);
++aboveMax3DTextureSize;
++aboveMaxTextureSize;
const char* message =
"GL_INVALID_VALUE is generated if width, height or depth is greater than GL_MAX_3D_TEXTURE_SIZE.";
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, aboveMax3DTextureSize, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, aboveMax3DTextureSize, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, aboveMax3DTextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, aboveMax3DTextureSize, aboveMax3DTextureSize, aboveMax3DTextureSize,
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
}
// invalid border
{
const char* message = "GL_INVALID_VALUE is generated if border is not 0 or 1.";
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 1, 1, 1, -1, GL_RGB, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 1, 1, 1, 2, GL_RGB, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
}
return STOP;
}
class NegativeCompressedTexImage3DCase : public Texture3DBase
{
public:
NegativeCompressedTexImage3DCase(deqp::Context& context, const char* name);
IterateResult iterate(void);
};
NegativeCompressedTexImage3DCase::NegativeCompressedTexImage3DCase(deqp::Context& context, const char* name)
: Texture3DBase(context, name, "")
{
}
class NegativeTexSubImage3DCase : public Texture3DBase
{
public:
NegativeTexSubImage3DCase(deqp::Context& context, const char* name);
IterateResult iterate(void);
};
NegativeTexSubImage3DCase::NegativeTexSubImage3DCase(deqp::Context& context, const char* name)
: Texture3DBase(context, name, "")
{
}
NegativeTexSubImage3DCase::IterateResult NegativeTexSubImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// negative usage
{
deUint32 texture = 0x1234;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
const char* message1 = "GL_INVALID_ENUM is generated if target is invalid.";
callTexSubImage3D(0, 0, 0, 0, 0, 4, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_ENUM, message1);
callTexSubImage3D(GL_TEXTURE_2D, 0, 0, 0, 0, 4, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_ENUM, message1);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 4, 4, 4, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if format is not an accepted format constant.");
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 4, 4, 4, GL_RGB, 0, 0);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if type is not a type constant.");
const char* message2 = "GL_INVALID_OPERATION is generated if the combination of internalFormat of "
"the previously specified texture array, format and type is not valid.";
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 4, 4, 4, GL_RGB, GL_UNSIGNED_SHORT_4_4_4_4, 0);
verifyError(GL_INVALID_OPERATION, message2);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 4, 4, 4, GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, 0);
verifyError(GL_INVALID_OPERATION, message2);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 4, 4, 4, GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, 0);
verifyError(GL_INVALID_OPERATION, message2);
gl.deleteTextures(1, &texture);
}
// negative level
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
const char* message = "GL_INVALID_VALUE is generated if level is less than 0.";
callTexSubImage3D(GL_TEXTURE_3D, -1, 0, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
gl.deleteTextures(1, &texture);
}
// maximal level
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
int maxSize;
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &maxSize);
GLint log2Max3DTextureSize = deLog2Floor32(maxSize) + 1;
callTexSubImage3D(GL_TEXTURE_3D, log2Max3DTextureSize, 0, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE,
"GL_INVALID_VALUE is generated if level is greater than log_2(GL_MAX_3D_TEXTURE_SIZE).");
gl.deleteTextures(1, &texture);
}
// negative offset
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
const char* message = "GL_INVALID_VALUE is generated if xoffset, yoffset or zoffset are negative.";
callTexSubImage3D(GL_TEXTURE_3D, 0, -1, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, -1, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, -1, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexSubImage3D(GL_TEXTURE_3D, 0, -1, -1, -1, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
gl.deleteTextures(1, &texture);
}
// invalid offset
{
deUint32 texture = 0x1234;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
callTexSubImage3D(GL_TEXTURE_3D, 0, 2, 0, 0, 4, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if xoffset + width > texture_width.");
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 2, 0, 4, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if yoffset + height > texture_height.");
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 2, 4, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if zoffset + depth > texture_depth.");
gl.deleteTextures(1, &texture);
}
// negative dimensions
{
const char* message = "GL_INVALID_VALUE is generated if width, height or depth is less than 0.";
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, -1, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, -1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, -1, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
callTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, -1, -1, -1, GL_RGBA, GL_UNSIGNED_BYTE, 0);
verifyError(GL_INVALID_VALUE, message);
}
return STOP;
}
class NegativeCopyTexSubImage3DCase : public Texture3DBase
{
public:
NegativeCopyTexSubImage3DCase(deqp::Context& context, const char* name);
IterateResult iterate(void);
};
NegativeCopyTexSubImage3DCase::NegativeCopyTexSubImage3DCase(deqp::Context& context, const char* name)
: Texture3DBase(context, name, "")
{
}
NegativeCopyTexSubImage3DCase::IterateResult NegativeCopyTexSubImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// invalid usage
{
GLuint texture = 0x1234;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
callCopyTexSubImage3D(0, 0, 0, 0, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if target is invalid.");
gl.deleteTextures(1, &texture);
}
// negative level
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
const char* message = "GL_INVALID_VALUE is generated if level is less than 0.";
callCopyTexSubImage3D(GL_TEXTURE_3D, -1, 0, 0, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, message);
gl.deleteTextures(1, &texture);
}
// maximal level
{
int maxSize;
int max3DSize;
gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DSize);
deUint32 log2Max3DTextureSize = deLog2Floor32(max3DSize) + 1;
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
callCopyTexSubImage3D(GL_TEXTURE_3D, log2Max3DTextureSize, 0, 0, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE,
"GL_INVALID_VALUE is generated if level is greater than log_2(GL_MAX_3D_TEXTURE_SIZE).");
gl.deleteTextures(1, &texture);
}
// negative offset
{
GLuint texture = 0x1234;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
const char* message = "GL_INVALID_VALUE is generated if xoffset, yoffset or zoffset is negative.";
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, -1, 0, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, message);
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, -1, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, message);
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, -1, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, message);
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, -1, -1, -1, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, message);
gl.deleteTextures(1, &texture);
}
// invalid offset
{
GLuint texture = 0x1234;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 1, 0, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if xoffset + width > texture_width.");
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 1, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if yoffset + height > texture_height.");
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 4, 0, 0, 4, 4);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if zoffset + 1 > texture_depth.");
gl.deleteTextures(1, &texture);
}
// negative dimensions
{
GLuint texture = 0x1234;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.getError(); // reset error
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, -4, 4);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if width < 0.");
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 4, -4);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if height < 0.");
gl.deleteTextures(1, &texture);
}
// incomplete_framebuffer
{
GLuint fbo = 0x1234;
GLuint texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
gl.genFramebuffers(1, &fbo);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER);
const char* message = "GL_INVALID_FRAMEBUFFER_OPERATION is generated if the currently "
"bound framebuffer is not framebuffer complete.";
callCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 4, 4);
verifyError(GL_INVALID_FRAMEBUFFER_OPERATION, message);
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
gl.deleteFramebuffers(1, &fbo);
gl.deleteTextures(1, &texture);
}
return STOP;
}
class NegativeFramebufferTexture3DCase : public Texture3DBase
{
public:
NegativeFramebufferTexture3DCase(deqp::Context& context, const char* name);
IterateResult iterate(void);
};
NegativeFramebufferTexture3DCase::NegativeFramebufferTexture3DCase(deqp::Context& context, const char* name)
: Texture3DBase(context, name, "")
{
}
NegativeFramebufferTexture3DCase::IterateResult NegativeFramebufferTexture3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
GLuint fbo = 0x1234;
gl.genFramebuffers(1, &fbo);
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
GLuint tex3D = 0x1234;
gl.genTextures(1, &tex3D);
gl.bindTexture(GL_TEXTURE_3D, tex3D);
GLint maxTexSize = 0x1234;
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE_OES, &maxTexSize);
gl.getError(); // reset error
callFramebufferTexture3D(-1, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, tex3D, 0, 0);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if target is not one of the accepted tokens.");
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex3D, 0, 0);
verifyError(GL_INVALID_OPERATION,
"GL_INVALID_OPERATION is generated if textarget is not an accepted texture target.");
callFramebufferTexture3D(GL_FRAMEBUFFER, -1, GL_TEXTURE_3D, tex3D, 0, 0);
verifyError(GL_INVALID_ENUM, "GL_INVALID_ENUM is generated if attachment is not an accepted token.");
const char* message1 =
"GL_INVALID_VALUE is generated if level is less than 0 or larger than log_2 of maximum texture size.";
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, tex3D, -1, 0);
verifyError(GL_INVALID_VALUE, message1);
GLint maxSize = deLog2Floor32(maxTexSize) + 1;
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, tex3D, maxSize, 0);
verifyError(GL_INVALID_VALUE, message1);
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, -1, 0, 0);
verifyError(
GL_INVALID_OPERATION,
"GL_INVALID_OPERATION is generated if texture is neither 0 nor the name of an existing texture object.");
const char* message2 = "GL_INVALID_OPERATION is generated if textarget and texture are not compatible.";
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, tex3D, 0, 0);
verifyError(GL_INVALID_OPERATION, message2);
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex3D, 0, 0);
verifyError(GL_INVALID_OPERATION, message2);
gl.deleteTextures(1, &tex3D);
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
callFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, 0, 0, 0);
verifyError(GL_INVALID_OPERATION, "GL_INVALID_OPERATION is generated if zero is bound to target.");
gl.deleteFramebuffers(1, &fbo);
return STOP;
}
NegativeCompressedTexImage3DCase::IterateResult NegativeCompressedTexImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
std::set<int> supportedFormats;
getSupportedCompressedFormats(supportedFormats);
if (supportedFormats.empty())
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "No supported compressed texture formats.");
return STOP;
}
GLenum supportedCompressedFormat = static_cast<GLenum>(*(supportedFormats.begin()));
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// negative usage
{
const char* message1 = "GL_INVALID_ENUM is generated if target is invalid.";
callCompressedTexImage3D(0, 0, supportedCompressedFormat, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_ENUM, message1);
callCompressedTexImage3D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, supportedCompressedFormat, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_ENUM, message1);
const char* message2 =
"GL_INVALID_ENUM is generated if internalformat is not one of the specific compressed internal formats.";
callCompressedTexImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_ENUM, message2);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_ENUM, message2);
const char* message3 = "INVALID_OPERATION is generated if internalformat is an ETC2/EAC format.";
for (int formatNdx = 0; formatNdx < tcu::COMPRESSEDTEXFORMAT_LAST; formatNdx++)
{
tcu::CompressedTexFormat format = static_cast<tcu::CompressedTexFormat>(formatNdx);
if (tcu::isEtcFormat(format) && (format != tcu::COMPRESSEDTEXFORMAT_ETC1_RGB8))
{
deUint32 compressedFormat = glu::getGLFormat(format);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, compressedFormat, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_OPERATION, message3);
}
}
}
// negative level
{
callCompressedTexImage3D(GL_TEXTURE_3D, -1, supportedCompressedFormat, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if level is less than 0.");
}
// maximal level
{
int maxSize;
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &maxSize);
GLint log2MaxTextureSize = deLog2Floor32(maxSize) + 1;
callCompressedTexImage3D(GL_TEXTURE_3D, log2MaxTextureSize, supportedCompressedFormat, 0, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_VALUE,
"GL_INVALID_VALUE is generated if level is greater than log_2(GL_MAX_TEXTURE_SIZE).");
}
// negative dimensions
{
const char* message = "GL_INVALID_VALUE is generated if width, height or depth is less than 0.";
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, -1, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, -1, 0, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, 0, -1, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, -1, -1, -1, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
}
// maximal dimensions
{
int maxTextureSize;
gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE_OES, &maxTextureSize);
++maxTextureSize;
const char* message =
"GL_INVALID_VALUE is generated if width, height or depth is greater than GL_MAX_3D_TEXTURE_SIZE_OES.";
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, maxTextureSize, 0, 0, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, maxTextureSize, 0, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, 0, maxTextureSize, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, maxTextureSize, maxTextureSize,
maxTextureSize, 0, 0, 0);
verifyError(GL_INVALID_VALUE, message);
}
// invalid border
{
const char* message = "GL_INVALID_VALUE is generated if border is not 0.";
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, 0, 0, -1, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, 0, 0, 1, 0, 0);
verifyError(GL_INVALID_VALUE, message);
}
// invalid size
{
const char* message = "GL_INVALID_VALUE is generated if imageSize is not consistent with the "
"format, dimensions, and contents of the specified compressed image data.";
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 0, 0, 0, 0, -1, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 16, 16, 1, 0, 9 * 4 * 8, 0);
verifyError(GL_INVALID_VALUE, message);
}
return STOP;
}
class NegativeCompressedTexSubImage3DCase : public Texture3DBase
{
public:
NegativeCompressedTexSubImage3DCase(deqp::Context& context, const char* name);
IterateResult iterate(void);
};
NegativeCompressedTexSubImage3DCase::NegativeCompressedTexSubImage3DCase(deqp::Context& context, const char* name)
: Texture3DBase(context, name, "")
{
}
NegativeCompressedTexSubImage3DCase::IterateResult NegativeCompressedTexSubImage3DCase::iterate(void)
{
if (!isFeatureSupported())
return STOP;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
std::set<int> supportedFormats;
getSupportedCompressedFormats(supportedFormats);
if (supportedFormats.empty())
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "No supported compressed texture formats.");
return STOP;
}
GLenum supportedCompressedFormat = static_cast<GLenum>(*(supportedFormats.begin()));
int textureSize = 16;
int dataSize = calculateDataSize(supportedCompressedFormat, textureSize, textureSize, 1);
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// negative level
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, textureSize, textureSize, 1, 0, dataSize,
0);
gl.getError(); // reset error
callCompressedTexSubImage3D(GL_TEXTURE_3D, -1, 0, 0, 0, 0, 0, 0, supportedCompressedFormat, 0, 0);
verifyError(GL_INVALID_VALUE, "GL_INVALID_VALUE is generated if level is less than 0.");
gl.deleteTextures(1, &texture);
}
// invalid level
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, textureSize, textureSize, 1, 0, dataSize,
0);
gl.getError(); // reset error
GLint log2MaxTextureSize = deLog2Floor32(m_context.getContextInfo().getInt(GL_MAX_3D_TEXTURE_SIZE)) + 1;
callCompressedTexSubImage3D(GL_TEXTURE_3D, log2MaxTextureSize, 0, 0, 0, 0, 0, 0, supportedCompressedFormat, 0,
0);
verifyError(GL_INVALID_VALUE,
"GL_INVALID_VALUE is generated if level is greater than log_2(GL_MAX_3D_TEXTURE_SIZE).");
gl.deleteTextures(1, &texture);
}
// negative offsets
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, textureSize, textureSize, 1, 0, dataSize,
0);
gl.getError(); // reset error
const char* message =
"GL_INVALID_VALUE or GL_INVALID_OPERATION is generated if xoffset, yoffset or zoffset are negative.";
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, -4, 0, 0, 0, 0, 0, supportedCompressedFormat, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, 0, -4, 0, 0, 0, 0, supportedCompressedFormat, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, -4, 0, 0, 0, supportedCompressedFormat, 0, 0);
verifyError(GL_INVALID_VALUE, message);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, -4, -4, -4, 0, 0, 0, supportedCompressedFormat, 0, 0);
verifyError(GL_INVALID_VALUE, message);
gl.deleteTextures(1, &texture);
}
// invalid offsets
{
deUint32 texture;
gl.genTextures(1, &texture);
gl.bindTexture(GL_TEXTURE_3D, texture);
dataSize = calculateDataSize(supportedCompressedFormat, 4, 4, 1);
callCompressedTexImage3D(GL_TEXTURE_3D, 0, supportedCompressedFormat, 4, 4, 1, 0, dataSize, 0);
gl.getError(); // reset error
const char* message = "GL_INVALID_VALUE or GL_INVALID_OPERATION is generated if xoffset + width > "
"texture_width or yoffset + height > texture_height.";
dataSize = calculateDataSize(supportedCompressedFormat, 8, 4, 1);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, 12, 0, 0, 8, 4, 1, supportedCompressedFormat, dataSize, 0);
verifyError(GL_INVALID_VALUE, GL_INVALID_OPERATION, message);
dataSize = calculateDataSize(supportedCompressedFormat, 4, 8, 1);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, 0, 12, 0, 4, 8, 1, supportedCompressedFormat, dataSize, 0);
verifyError(GL_INVALID_VALUE, GL_INVALID_OPERATION, message);
dataSize = calculateDataSize(supportedCompressedFormat, 4, 4, 1);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 12, 4, 4, 1, supportedCompressedFormat, dataSize, 0);
verifyError(GL_INVALID_VALUE, GL_INVALID_OPERATION, message);
dataSize = calculateDataSize(supportedCompressedFormat, 8, 8, 1);
callCompressedTexSubImage3D(GL_TEXTURE_3D, 0, 12, 12, 12, 8, 8, 1, supportedCompressedFormat, dataSize, 0);
verifyError(GL_INVALID_VALUE, GL_INVALID_OPERATION, message);
gl.deleteTextures(1, &texture);
}
return STOP;
}
Texture3DTests::Texture3DTests(deqp::Context& context) : TestCaseGroup(context, "texture_3d", "")
{
}
Texture3DTests::~Texture3DTests(void)
{
}
void Texture3DTests::init()
{
static const struct
{
const char* name;
GLint mode;
} wrapModes[] = { { "clamp", GL_CLAMP_TO_EDGE }, { "repeat", GL_REPEAT }, { "mirror", GL_MIRRORED_REPEAT } };
static const struct
{
const char* name;
GLint 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;
GLint mode;
} magFilterModes[] = { { "nearest", GL_NEAREST }, { "linear", GL_LINEAR } };
static const struct
{
int width;
int height;
int depth;
} sizes[] = { { 4, 8, 8 }, { 32, 64, 16 }, { 128, 32, 64 }, { 3, 7, 5 }, { 63, 63, 63 } };
static const struct
{
const char* name;
deUint32 format;
deUint32 type;
} filterableFormatsByType[] = {
{ "rgba", GL_RGBA, GL_UNSIGNED_BYTE },
};
static const struct
{
const char* name;
deUint32 format;
} sizedFilterableFormatsByType[] = {
{ "rgba8", GL_RGBA8 },
};
static const struct
{
tcu::CompressedTexFormat fmt;
} compressedFormats[] = {
{tcu::COMPRESSEDTEXFORMAT_ETC1_RGB8},
{tcu::COMPRESSEDTEXFORMAT_EAC_R11},
{tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_R11},
{tcu::COMPRESSEDTEXFORMAT_EAC_RG11},
{tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11},
{tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8},
{tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8},
{tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1},
{tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1},
{tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8},
{tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA},
{tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8},
{tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8},
};
// Texture3DFilteringCase
{
deqp::TestCaseGroup* texFilteringGroup =
new deqp::TestCaseGroup(m_context, "filtering", "3D Texture Filtering");
addChild(texFilteringGroup);
// Formats.
FilteringData data;
deqp::TestCaseGroup* formatsGroup = new deqp::TestCaseGroup(m_context, "formats", "3D Texture Formats");
texFilteringGroup->addChild(formatsGroup);
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(sizedFilterableFormatsByType); fmtNdx++)
{
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
{
data.minFilter = minFilterModes[filterNdx].mode;
bool isMipmap = data.minFilter != GL_NEAREST && data.minFilter != GL_LINEAR;
data.magFilter = isMipmap ? GL_LINEAR : data.minFilter;
data.internalFormat = sizedFilterableFormatsByType[fmtNdx].format;
data.wrapS = GL_REPEAT;
data.wrapT = GL_REPEAT;
data.wrapR = GL_REPEAT;
data.width = 64;
data.height = 64;
data.depth = 64;
const char* formatName = sizedFilterableFormatsByType[fmtNdx].name;
const char* filterName = minFilterModes[filterNdx].name;
std::string name = std::string(formatName) + "_" + filterName;
formatsGroup->addChild(new Texture3DFilteringCase(m_context, name.c_str(), "", data));
}
}
// Sizes.
deqp::TestCaseGroup* sizesGroup = new deqp::TestCaseGroup(m_context, "sizes", "Texture Sizes");
texFilteringGroup->addChild(sizesGroup);
for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); sizeNdx++)
{
for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
{
data.minFilter = minFilterModes[filterNdx].mode;
data.internalFormat = GL_RGBA8;
bool isMipmap = data.minFilter != GL_NEAREST && data.minFilter != GL_LINEAR;
data.magFilter = isMipmap ? GL_LINEAR : data.minFilter;
data.wrapS = GL_REPEAT;
data.wrapT = GL_REPEAT;
data.wrapR = GL_REPEAT;
data.width = sizes[sizeNdx].width;
data.height = sizes[sizeNdx].height;
data.depth = sizes[sizeNdx].depth;
const char* filterName = minFilterModes[filterNdx].name;
std::string name = de::toString(data.width) + "x" + de::toString(data.height) + "x" +
de::toString(data.depth) + "_" + filterName;
sizesGroup->addChild(new Texture3DFilteringCase(m_context, name.c_str(), "", data));
}
}
// Wrap modes.
deqp::TestCaseGroup* combinationsGroup =
new deqp::TestCaseGroup(m_context, "combinations", "Filter and wrap mode combinations");
texFilteringGroup->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++)
{
for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++)
{
data.minFilter = minFilterModes[minFilterNdx].mode;
data.magFilter = magFilterModes[magFilterNdx].mode;
data.internalFormat = GL_RGBA8;
data.wrapS = wrapModes[wrapSNdx].mode;
data.wrapT = wrapModes[wrapTNdx].mode;
data.wrapR = wrapModes[wrapRNdx].mode;
data.width = 63;
data.height = 57;
data.depth = 67;
std::string name = std::string(minFilterModes[minFilterNdx].name) + "_" +
magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name +
"_" + wrapModes[wrapTNdx].name + "_" + wrapModes[wrapRNdx].name;
combinationsGroup->addChild(new Texture3DFilteringCase(m_context, name.c_str(), "", data));
}
}
}
}
}
// negative tests.
combinationsGroup->addChild(new NegativeTexImage3DCase(m_context, "negative"));
}
// TexSubImage3DOES tests
{
tcu::TestCaseGroup* texSubImageGroup =
new tcu::TestCaseGroup(m_testCtx, "sub_image", "Basic glTexSubImage3D() usage");
addChild(texSubImageGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(sizedFilterableFormatsByType); formatNdx++)
{
const char* fmtName = sizedFilterableFormatsByType[formatNdx].name;
deUint32 format = sizedFilterableFormatsByType[formatNdx].format;
texSubImageGroup->addChild(new TexSubImage3DCase(m_context, fmtName, "", format, 32, 64, 8));
}
texSubImageGroup->addChild(new NegativeTexSubImage3DCase(m_context, "negative"));
}
// CopyTexSubImage3DOES tests
{
tcu::TestCaseGroup* copyTexSubImageGroup =
new tcu::TestCaseGroup(m_testCtx, "copy_sub_image", "Basic glCopyTexSubImage3D() usage");
addChild(copyTexSubImageGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); formatNdx++)
{
const char* fmtName = filterableFormatsByType[formatNdx].name;
deUint32 format = filterableFormatsByType[formatNdx].format;
deUint32 type = filterableFormatsByType[formatNdx].type;
copyTexSubImageGroup->addChild(new CopyTexSubImage3DCase(m_context, fmtName, "", format, type, 32, 64, 8));
}
copyTexSubImageGroup->addChild(new NegativeCopyTexSubImage3DCase(m_context, "negative"));
}
// FramebufferTexture3DOES tests
{
tcu::TestCaseGroup* framebufferTextureGroup =
new tcu::TestCaseGroup(m_testCtx, "framebuffer_texture", "Basic glFramebufferTexture3D() usage");
addChild(framebufferTextureGroup);
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); formatNdx++)
{
const char* fmtName = filterableFormatsByType[formatNdx].name;
deUint32 format = filterableFormatsByType[formatNdx].format;
deUint32 type = filterableFormatsByType[formatNdx].type;
framebufferTextureGroup->addChild(new FramebufferTexture3DCase(m_context, fmtName, "", format, type, 64, 64, 3));
}
framebufferTextureGroup->addChild(new NegativeFramebufferTexture3DCase(m_context, "negative"));
}
// CompressedTexImage3DOES and CompressedTexSubImage3DOES tests
{
tcu::TestCaseGroup* compressedTexGroup =
new tcu::TestCaseGroup(m_testCtx, "compressed_texture", "Basic gl.compressedTexImage3D() usage");
for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(compressedFormats); formatNdx++)
{
// ETC2/EAC texture compression algorithm supports only two-dimensional images
tcu::CompressedTexFormat format = static_cast<tcu::CompressedTexFormat>(formatNdx);
if (tcu::isEtcFormat(format))
continue;
deUint32 compressedFormat = glu::getGLFormat(format);
const char* name = getCompressedFormatName(format);
compressedTexGroup->addChild(new CompressedTexture3DCase(m_context, name, compressedFormat));
}
compressedTexGroup->addChild(new NegativeCompressedTexImage3DCase(m_context, "negative_compressed_tex_image"));
compressedTexGroup->addChild(
new NegativeCompressedTexSubImage3DCase(m_context, "negative_compressed_tex_sub_image"));
addChild(compressedTexGroup);
}
}
} // glcts namespace