/*------------------------------------------------------------------------- * 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 using namespace glw; using namespace glu::TextureTestUtil; namespace es2cts { enum { VIEWPORT_WIDTH = 64, VIEWPORT_HEIGHT = 64, }; typedef std::pair 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 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& validFormats) const; int calculateDataSize(deUint32 formats, int width, int height, int depth) const; template 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& 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(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 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 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(expectedError)) << " was expected but got " << glu::getErrorStr(static_cast(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(expectedError1)) << " or " << glu::getErrorStr(static_cast(expectedError1)) << " was expected but got " << glu::getErrorStr(static_cast(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(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 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(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(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(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(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_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(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; } void checkFormatSupport(const glu::ContextInfo& info, deUint32 format) { if (glu::isCompressedFormat(format)) { if (isAstcFormat(glu::mapGLCompressedTexFormat(format))) { if (!info.isExtensionSupported("GL_KHR_texture_compression_astc_hdr") && !info.isExtensionSupported("GL_OES_texture_compression_astc")) { TCU_THROW(NotSupportedError, "requires HDR astc support."); } } } } 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(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; } checkFormatSupport(contextInfo, m_compressedFormat); 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(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(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(); /* Integer textures supported for OpenGL ES 3.0+ */ int major = 0; gl.getIntegerv(GL_MAJOR_VERSION, &major); bool supportsIntegerTextures = major >= 3; 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); if (supportsIntegerTextures) { 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_FRAMEBUFFER, fbo); gl.checkFramebufferStatus(GL_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(); const glu::ContextInfo& contextInfo = m_context.getContextInfo(); std::set 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(*(supportedFormats.begin())); checkFormatSupport(contextInfo, supportedCompressedFormat); 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(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(); const glu::ContextInfo& contextInfo = m_context.getContextInfo(); std::set 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(*(supportedFormats.begin())); int textureSize = 16; int dataSize = calculateDataSize(supportedCompressedFormat, textureSize, textureSize, 1); checkFormatSupport(contextInfo, supportedCompressedFormat); 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(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