blob: 0560212a4c6ad73560be9fd43f0cbc028d26d459 [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 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;
};
CopyTexSubImage3DCase::CopyTexSubImage3DCase(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))
{
}
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_internalFormat, m_width, m_height, m_depth);
const tcu::TextureFormat textureFormat = texture.getRefTexture().getFormat();
const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(textureFormat);
/* According to the spec, the component sizes of internalformat should exactly match the corresponding component sizes
of the source buffer's effective internal format when call the glCopyTexSubImage3D function. Because the test format
is GL_RGBA8, so we should create a new texture with the same format and attach it to a new fbo. */
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, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, 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 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;
};
FramebufferTexture3DCase::FramebufferTexture3DCase(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))
{
}
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_internalFormat, m_width, m_height, m_depth);
glu::Texture2D texture2D(m_context.getRenderContext(), m_internalFormat, 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_TEXTURE_SIZE, &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_RGBA8, 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_TEXTURE_SIZE, &maxTextureSize);
++maxTextureSize;
const char* message =
"GL_INVALID_VALUE is generated if width, height or depth is greater than GL_MAX_TEXTURE_SIZE.";
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;
} filterableFormatsByType[] = {
{ "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(filterableFormatsByType); 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 = filterableFormatsByType[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 = filterableFormatsByType[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(filterableFormatsByType); formatNdx++)
{
const char* fmtName = filterableFormatsByType[formatNdx].name;
deUint32 format = filterableFormatsByType[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;
copyTexSubImageGroup->addChild(new CopyTexSubImage3DCase(m_context, fmtName, "", format, 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;
framebufferTextureGroup->addChild(new FramebufferTexture3DCase(m_context, fmtName, "", format, 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