/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.1 Module * ------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Texture level state query tests *//*--------------------------------------------------------------------*/ #include "es31fTextureLevelStateQueryTests.hpp" #include "glsStateQueryUtil.hpp" #include "tcuTestLog.hpp" #include "gluRenderContext.hpp" #include "gluCallLogWrapper.hpp" #include "gluTextureUtil.hpp" #include "gluStrUtil.hpp" #include "gluContextInfo.hpp" #include "glwFunctions.hpp" #include "glwEnums.hpp" #include "tcuTextureUtil.hpp" #include "tcuFormatUtil.hpp" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" namespace deqp { namespace gles31 { namespace Functional { namespace { using namespace gls::StateQueryUtil; static bool textureTypeHasDepth (glw::GLenum textureBindTarget) { switch (textureBindTarget) { case GL_TEXTURE_2D: return false; case GL_TEXTURE_3D: return true; case GL_TEXTURE_2D_ARRAY: return true; case GL_TEXTURE_CUBE_MAP: return false; case GL_TEXTURE_2D_MULTISAMPLE: return false; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: return true; case GL_TEXTURE_BUFFER: return false; case GL_TEXTURE_CUBE_MAP_ARRAY: return true; default: DE_ASSERT(DE_FALSE); return false; } } static bool textureTypeHasHeight (glw::GLenum textureBindTarget) { switch (textureBindTarget) { case GL_TEXTURE_2D: return true; case GL_TEXTURE_3D: return true; case GL_TEXTURE_2D_ARRAY: return true; case GL_TEXTURE_CUBE_MAP: return true; case GL_TEXTURE_2D_MULTISAMPLE: return true; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: return true; case GL_TEXTURE_BUFFER: return false; case GL_TEXTURE_CUBE_MAP_ARRAY: return true; default: DE_ASSERT(DE_FALSE); return false; } } static const char* getTextureTargetExtension (glw::GLenum target) { switch (target) { case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: return "GL_OES_texture_storage_multisample_2d_array"; case GL_TEXTURE_BUFFER: return "GL_EXT_texture_buffer"; case GL_TEXTURE_CUBE_MAP_ARRAY: return "GL_EXT_texture_cube_map_array"; default: DE_ASSERT(DE_FALSE); return DE_NULL; } } static bool isCoreTextureTarget (glw::GLenum target, const glu::ContextType& contextType) { switch (target) { case GL_TEXTURE_2D: case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_2D_MULTISAMPLE: return true; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: case GL_TEXTURE_BUFFER: case GL_TEXTURE_CUBE_MAP_ARRAY: return glu::contextSupports(contextType, glu::ApiType::es(3, 2)) || glu::contextSupports(contextType, glu::ApiType::core(4, 5)); default: return false; } } struct TextureGenerationSpec { struct TextureLevelSpec { int width; int height; int depth; int level; glw::GLenum internalFormat; bool compressed; TextureLevelSpec (void) : width (0) , height (0) , depth (0) , level (0) , internalFormat (GL_RGBA) , compressed (false) { } }; glw::GLenum bindTarget; glw::GLenum queryTarget; bool immutable; bool fixedSamplePos; // !< fixed sample pos argument for multisample textures int sampleCount; int texBufferDataOffset; int texBufferDataSize; bool bindWholeArray; std::vector levels; std::string description; TextureGenerationSpec (void) : immutable (true) , fixedSamplePos (true) , sampleCount (0) , texBufferDataOffset (0) , texBufferDataSize (256) , bindWholeArray (false) { } }; struct IntegerPrinter { static std::string getIntegerName (int v) { return de::toString(v); } static std::string getFloatName (float v) { return de::toString(v); } }; struct PixelFormatPrinter { static std::string getIntegerName (int v) { return de::toString(glu::getTextureFormatStr(v)); } static std::string getFloatName (float v) { return de::toString(glu::getTextureFormatStr((int)v)); } }; template static bool verifyTextureLevelParameterEqualWithPrinter (glu::CallLogWrapper& gl, glw::GLenum target, int level, glw::GLenum pname, int refValue, QueryType type) { QueriedState state; tcu::ResultCollector result (gl.getLog(), " // ERROR: "); gl.getLog() << tcu::TestLog::Message << "Verifying " << glu::getTextureLevelParameterStr(pname) << ", expecting " << Printer::getIntegerName(refValue) << tcu::TestLog::EndMessage; queryTextureLevelState(result, gl, type, target, level, pname, state); if (state.isUndefined()) return false; verifyInteger(result, state, refValue); return result.getResult() == QP_TEST_RESULT_PASS; } static bool verifyTextureLevelParameterEqual (glu::CallLogWrapper& gl, glw::GLenum target, int level, glw::GLenum pname, int refValue, QueryType type) { return verifyTextureLevelParameterEqualWithPrinter(gl, target, level, pname, refValue, type); } static bool verifyTextureLevelParameterInternalFormatEqual (glu::CallLogWrapper& gl, glw::GLenum target, int level, glw::GLenum pname, int refValue, QueryType type) { return verifyTextureLevelParameterEqualWithPrinter(gl, target, level, pname, refValue, type); } static bool verifyTextureLevelParameterGreaterOrEqual (glu::CallLogWrapper& gl, glw::GLenum target, int level, glw::GLenum pname, int refValue, QueryType type) { QueriedState state; tcu::ResultCollector result (gl.getLog(), " // ERROR: "); gl.getLog() << tcu::TestLog::Message << "Verifying " << glu::getTextureLevelParameterStr(pname) << ", expecting " << refValue << " or greater" << tcu::TestLog::EndMessage; queryTextureLevelState(result, gl, type, target, level, pname, state); if (state.isUndefined()) return false; verifyIntegerMin(result, state, refValue); return result.getResult() == QP_TEST_RESULT_PASS; } static bool verifyTextureLevelParameterInternalFormatAnyOf (glu::CallLogWrapper& gl, glw::GLenum target, int level, glw::GLenum pname, const int* refValues, int numRefValues, QueryType type) { QueriedState state; tcu::ResultCollector result (gl.getLog(), " // ERROR: "); // Log what we try to do { tcu::MessageBuilder msg(&gl.getLog()); msg << "Verifying " << glu::getTextureLevelParameterStr(pname) << ", expecting any of {"; for (int ndx = 0; ndx < numRefValues; ++ndx) { if (ndx != 0) msg << ", "; msg << glu::getTextureFormatStr(refValues[ndx]); } msg << "}"; msg << tcu::TestLog::EndMessage; } queryTextureLevelState(result, gl, type, target, level, pname, state); if (state.isUndefined()) return false; // verify switch (state.getType()) { case DATATYPE_INTEGER: { for (int ndx = 0; ndx < numRefValues; ++ndx) if (state.getIntAccess() == refValues[ndx]) return true; gl.getLog() << tcu::TestLog::Message << "Error: got " << state.getIntAccess() << ", (" << glu::getTextureFormatStr(state.getIntAccess()) << ")" << tcu::TestLog::EndMessage; return false; } case DATATYPE_FLOAT: { for (int ndx = 0; ndx < numRefValues; ++ndx) if (state.getFloatAccess() == (float)refValues[ndx]) return true; gl.getLog() << tcu::TestLog::Message << "Error: got " << state.getFloatAccess() << ", (" << glu::getTextureFormatStr((int)state.getFloatAccess()) << ")" << tcu::TestLog::EndMessage; return false; } default: DE_ASSERT(DE_FALSE); return false; } } static bool isDepthFormat (const tcu::TextureFormat& fmt) { return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS; } static bool isColorRenderableFormat (glw::GLenum internalFormat) { return internalFormat == GL_RGB565 || internalFormat == GL_RGBA4 || internalFormat == GL_RGB5_A1 || internalFormat == GL_RGB10_A2 || internalFormat == GL_RGB10_A2UI || internalFormat == GL_SRGB8_ALPHA8 || internalFormat == GL_R8 || internalFormat == GL_RG8 || internalFormat == GL_RGB8 || internalFormat == GL_RGBA8 || internalFormat == GL_R8I || internalFormat == GL_RG8I || internalFormat == GL_RGBA8I || internalFormat == GL_R8UI || internalFormat == GL_RG8UI || internalFormat == GL_RGBA8UI || internalFormat == GL_R16I || internalFormat == GL_RG16I || internalFormat == GL_RGBA16I || internalFormat == GL_R16UI || internalFormat == GL_RG16UI || internalFormat == GL_RGBA16UI || internalFormat == GL_R32I || internalFormat == GL_RG32I || internalFormat == GL_RGBA32I || internalFormat == GL_R32UI || internalFormat == GL_RG32UI || internalFormat == GL_RGBA32UI; } static bool isRenderableFormat (glw::GLenum internalFormat) { return isColorRenderableFormat(internalFormat) || internalFormat == GL_DEPTH_COMPONENT16 || internalFormat == GL_DEPTH_COMPONENT24 || internalFormat == GL_DEPTH_COMPONENT32F || internalFormat == GL_DEPTH24_STENCIL8 || internalFormat == GL_DEPTH32F_STENCIL8; } static bool isTextureBufferFormat (glw::GLenum internalFormat) { return internalFormat == GL_R8 || internalFormat == GL_R16F || internalFormat == GL_R32F || internalFormat == GL_R8I || internalFormat == GL_R16I || internalFormat == GL_R32I || internalFormat == GL_R8UI || internalFormat == GL_R16UI || internalFormat == GL_R32UI || internalFormat == GL_RG8 || internalFormat == GL_RG16F || internalFormat == GL_RG32F || internalFormat == GL_RG8I || internalFormat == GL_RG16I || internalFormat == GL_RG32I || internalFormat == GL_RG8UI || internalFormat == GL_RG16UI || internalFormat == GL_RG32UI || internalFormat == GL_RGB32F || internalFormat == GL_RGB32I || internalFormat == GL_RGB32UI || internalFormat == GL_RGBA8 || internalFormat == GL_RGBA16F || internalFormat == GL_RGBA32F || internalFormat == GL_RGBA8I || internalFormat == GL_RGBA16I || internalFormat == GL_RGBA32I || internalFormat == GL_RGBA8UI || internalFormat == GL_RGBA16UI || internalFormat == GL_RGBA32UI; } static bool isLegalFormatForTarget (glw::GLenum target, glw::GLenum format) { const tcu::TextureFormat fmt = glu::mapGLInternalFormat(format); if (target == GL_TEXTURE_3D && isDepthFormat(fmt)) return false; if ((target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) && !isRenderableFormat(format)) return false; if (target == GL_TEXTURE_BUFFER || !isTextureBufferFormat(format)) return false; return true; } static bool isCompressionSupportedForTarget (glw::GLenum target) { return target == GL_TEXTURE_2D || target == GL_TEXTURE_2D_ARRAY; } static bool isMultisampleTarget (glw::GLenum target) { return target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY; } static bool targetSupportsMipLevels (glw::GLenum target) { return target != GL_TEXTURE_2D_MULTISAMPLE && target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY && target != GL_TEXTURE_BUFFER; } static int getPixelSize (glw::GLenum internalFormat) { const tcu::TextureFormat fmt = glu::mapGLInternalFormat(internalFormat); return fmt.getPixelSize(); } static void generateColorTextureGenerationGroup (std::vector& group, glw::GLenum target, int maxSamples, glw::GLenum internalFormat) { const glw::GLenum queryTarget = (target == GL_TEXTURE_CUBE_MAP) ? (GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) : (target); // initial { TextureGenerationSpec texGen; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = 0; texGen.description = glu::getTextureTargetStr(target).toString() + ", initial values"; group.push_back(texGen); } // ms targets if (isMultisampleTarget(target)) { { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = 1; texGen.fixedSamplePos = false; texGen.description = glu::getTextureTargetStr(target).toString() + ", low sample count"; level.width = 16; level.height = 16; level.depth = (textureTypeHasDepth(texGen.bindTarget)) ? (6) : (1); level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = maxSamples; texGen.fixedSamplePos = false; texGen.description = glu::getTextureTargetStr(target).toString() + ", high sample count"; level.width = 32; level.height = 32; level.depth = (textureTypeHasDepth(texGen.bindTarget)) ? (6) : (1); level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = maxSamples; texGen.fixedSamplePos = true; texGen.description = glu::getTextureTargetStr(target).toString() + ", fixed sample positions"; level.width = 32; level.height = 32; level.depth = (textureTypeHasDepth(texGen.bindTarget)) ? (6) : (1); level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } } else if (target == GL_TEXTURE_BUFFER) { // whole buffer { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; const int baseSize = getPixelSize(internalFormat); texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.description = glu::getTextureTargetStr(target).toString() + ", whole buffer"; texGen.texBufferDataOffset = 0; texGen.texBufferDataSize = 32 * baseSize + (baseSize - 1); texGen.bindWholeArray = true; level.width = 32; level.height = 1; level.depth = 1; level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } // partial buffer { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; const int baseSize = getPixelSize(internalFormat); texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.description = glu::getTextureTargetStr(target).toString() + ", partial buffer"; texGen.texBufferDataOffset = 256; texGen.texBufferDataSize = 16 * baseSize + (baseSize - 1); texGen.bindWholeArray = false; level.width = 16; level.height = 1; level.depth = 1; level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } } else { // immutable { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.description = glu::getTextureTargetStr(target).toString() + ", immutable"; level.width = 32; level.height = 32; level.depth = (textureTypeHasDepth(texGen.bindTarget)) ? (6) : (1); level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } // mutable { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = false; texGen.description = glu::getTextureTargetStr(target).toString() + ", mutable"; level.width = 16; level.height = (target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) ? (16) : (64); level.depth = (textureTypeHasDepth(texGen.bindTarget)) ? (6) : (1); level.level = 0; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } // mip3 { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = false; texGen.description = glu::getTextureTargetStr(target).toString() + ", mip level 3"; level.width = 4; level.height = (target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) ? (4) : (8); level.depth = (textureTypeHasDepth(texGen.bindTarget)) ? (6) : (1); level.level = 3; level.internalFormat = internalFormat; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } } } static void generateInternalFormatTextureGenerationGroup (std::vector& group, glw::GLenum target) { const glw::GLenum queryTarget = (target == GL_TEXTURE_CUBE_MAP) ? (GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) : (target); // Internal formats static const glw::GLenum internalFormats[] = { GL_R8, GL_R8_SNORM, GL_RG8, GL_RG8_SNORM, GL_RGB8, GL_RGB8_SNORM, GL_RGB565, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGBA8_SNORM, GL_RGB10_A2, GL_RGB10_A2UI, GL_SRGB8, GL_SRGB8_ALPHA8, GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F, GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F, GL_R11F_G11F_B10F, GL_RGB9_E5, GL_R8I, GL_R8UI, GL_R16I, GL_R16UI, GL_R32I, GL_R32UI, GL_RG8I, GL_RG8UI, GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI, GL_RGB8I, GL_RGB8UI, GL_RGB16I, GL_RGB16UI, GL_RGB32I, GL_RGB32UI, GL_RGBA8I, GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16, GL_DEPTH32F_STENCIL8, GL_DEPTH24_STENCIL8 }; // initial { TextureGenerationSpec texGen; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = 0; texGen.fixedSamplePos = true; texGen.description = glu::getTextureTargetStr(target).toString() + ", initial values"; group.push_back(texGen); } // test all formats for (int internalFormatNdx = 0; internalFormatNdx < DE_LENGTH_OF_ARRAY(internalFormats); ++internalFormatNdx) { if (!isLegalFormatForTarget(target, internalFormats[internalFormatNdx])) continue; const int baseSize = getPixelSize(internalFormats[internalFormatNdx]); TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = (isMultisampleTarget(target) ? (1) : (0)); texGen.description = glu::getTextureTargetStr(target).toString() + ", internal format " + glu::getTextureFormatName(internalFormats[internalFormatNdx]); if (target == GL_TEXTURE_BUFFER) { texGen.texBufferDataOffset = 0; texGen.texBufferDataSize = 32 * baseSize + (baseSize - 1); texGen.bindWholeArray = true; } level.width = 32; level.height = (textureTypeHasHeight(target)) ? (32) : (1); level.depth = (textureTypeHasDepth(target)) ? (6) : (1); level.level = 0; level.internalFormat = internalFormats[internalFormatNdx]; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } // test mutable rgba8 with mip level 3 if (targetSupportsMipLevels(target)) { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = false; texGen.description = glu::getTextureTargetStr(target).toString() + ", internal format GL_RGBA8, mip level 3"; level.width = 32; level.height = 32; level.depth = (textureTypeHasDepth(target)) ? (6) : (1); level.level = 3; level.internalFormat = GL_RGBA8; level.compressed = false; texGen.levels.push_back(level); group.push_back(texGen); } } static void generateCompressedTextureGenerationGroup (std::vector& group, glw::GLenum target) { const glw::GLenum queryTarget = (target == GL_TEXTURE_CUBE_MAP) ? (GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) : (target); // initial { TextureGenerationSpec texGen; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.description = glu::getTextureTargetStr(target).toString() + ", initial values"; group.push_back(texGen); } // compressed if (isCompressionSupportedForTarget(target)) { TextureGenerationSpec texGen; TextureGenerationSpec::TextureLevelSpec level; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = false; texGen.description = glu::getTextureTargetStr(target).toString() + ", compressed"; level.width = 32; level.height = 32; level.depth = (target == GL_TEXTURE_2D_ARRAY) ? (2) : (1); level.level = 0; level.internalFormat = GL_COMPRESSED_RGB8_ETC2; level.compressed = true; texGen.levels.push_back(level); group.push_back(texGen); } } static void generateTextureBufferGenerationGroup (std::vector& group, glw::GLenum target) { const glw::GLenum queryTarget = (target == GL_TEXTURE_CUBE_MAP) ? (GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) : (target); // initial { TextureGenerationSpec texGen; texGen.bindTarget = target; texGen.queryTarget = queryTarget; texGen.immutable = true; texGen.sampleCount = 0; texGen.description = glu::getTextureTargetStr(target).toString() + ", initial values"; group.push_back(texGen); } // actual specification tests are in texture_buffer tests, no need to do them here too } bool applyTextureGenerationSpec (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec, glw::GLuint& texBuffer) { bool allOk = true; DE_ASSERT(!(spec.immutable && spec.levels.size() > 1)); // !< immutable textures have only one level for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const glu::TransferFormat transferFormat = (spec.levels[levelNdx].compressed) ? (glu::TransferFormat()) : (glu::getTransferFormat(glu::mapGLInternalFormat(spec.levels[levelNdx].internalFormat))); if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D) gl.glTexStorage2D(spec.bindTarget, 1, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height); else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_3D) gl.glTexStorage3D(spec.bindTarget, 1, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth); else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D_ARRAY) gl.glTexStorage3D(spec.bindTarget, 1, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth); else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_CUBE_MAP) gl.glTexStorage2D(spec.bindTarget, 1, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height); else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D_MULTISAMPLE) gl.glTexStorage2DMultisample(spec.bindTarget, spec.sampleCount, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, (spec.fixedSamplePos) ? (GL_TRUE) : (GL_FALSE)); else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) gl.glTexStorage3DMultisample(spec.bindTarget, spec.sampleCount, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth, (spec.fixedSamplePos) ? (GL_TRUE) : (GL_FALSE)); else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_CUBE_MAP_ARRAY) gl.glTexStorage3D(spec.bindTarget, 1, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth); else if (!spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D) gl.glTexImage2D(spec.bindTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, 0, transferFormat.format, transferFormat.dataType, DE_NULL); else if (!spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_3D) gl.glTexImage3D(spec.bindTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth, 0, transferFormat.format, transferFormat.dataType, DE_NULL); else if (!spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D_ARRAY) gl.glTexImage3D(spec.bindTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth, 0, transferFormat.format, transferFormat.dataType, DE_NULL); else if (!spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_CUBE_MAP) gl.glTexImage2D(spec.queryTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, 0, transferFormat.format, transferFormat.dataType, DE_NULL); else if (!spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_CUBE_MAP_ARRAY) gl.glTexImage3D(spec.bindTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth, 0, transferFormat.format, transferFormat.dataType, DE_NULL); else if (!spec.immutable && spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D) { DE_ASSERT(spec.levels[levelNdx].width == 32); DE_ASSERT(spec.levels[levelNdx].height == 32); DE_ASSERT(spec.levels[levelNdx].internalFormat == GL_COMPRESSED_RGB8_ETC2); static const deUint8 buffer[64 * 8] = { 0 }; gl.glCompressedTexImage2D(spec.bindTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, 0, sizeof(buffer), buffer); } else if (!spec.immutable && spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_2D_ARRAY) { DE_ASSERT(spec.levels[levelNdx].width == 32); DE_ASSERT(spec.levels[levelNdx].height == 32); DE_ASSERT(spec.levels[levelNdx].depth == 2); DE_ASSERT(spec.levels[levelNdx].internalFormat == GL_COMPRESSED_RGB8_ETC2); static const deUint8 buffer[64 * 8 * 2] = { 0 }; gl.glCompressedTexImage3D(spec.bindTarget, spec.levels[levelNdx].level, spec.levels[levelNdx].internalFormat, spec.levels[levelNdx].width, spec.levels[levelNdx].height, spec.levels[levelNdx].depth, 0, sizeof(buffer), buffer); } else if (spec.immutable && !spec.levels[levelNdx].compressed && spec.bindTarget == GL_TEXTURE_BUFFER) { gl.glGenBuffers(1, &texBuffer); gl.glBindBuffer(GL_TEXTURE_BUFFER, texBuffer); if (spec.bindWholeArray) { gl.glBufferData(GL_TEXTURE_BUFFER, spec.texBufferDataSize, DE_NULL, GL_STATIC_DRAW); gl.glTexBuffer(GL_TEXTURE_BUFFER, spec.levels[levelNdx].internalFormat, texBuffer); } else { gl.glBufferData(GL_TEXTURE_BUFFER, spec.texBufferDataOffset + spec.texBufferDataSize, DE_NULL, GL_STATIC_DRAW); gl.glTexBufferRange(GL_TEXTURE_BUFFER, spec.levels[levelNdx].internalFormat, texBuffer, spec.texBufferDataOffset, spec.texBufferDataSize); } } else DE_ASSERT(DE_FALSE); { const glw::GLenum err = gl.glGetError(); if (err != GL_NO_ERROR) { gl.getLog() << tcu::TestLog::Message << "Texture specification failed, got " + glu::getErrorStr(err).toString() << tcu::TestLog::EndMessage; allOk = false; } } } return allOk; } class TextureLevelCase : public TestCase { public: TextureLevelCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type); ~TextureLevelCase (void); void init (void); void deinit (void); IterateResult iterate (void); protected: void getFormatSamples (glw::GLenum internalFormat, std::vector& samples); bool testConfig (const TextureGenerationSpec& spec); virtual bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) = 0; virtual void generateTestIterations (std::vector& iterations) = 0; const QueryType m_type; const glw::GLenum m_target; glw::GLuint m_texture; glw::GLuint m_texBuffer; private: int m_iteration; std::vector m_iterations; bool m_allIterationsOk; std::vector m_failedIterations; }; TextureLevelCase::TextureLevelCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TestCase (ctx, name, desc) , m_type (type) , m_target (target) , m_texture (0) , m_texBuffer (0) , m_iteration (0) , m_allIterationsOk (true) { } TextureLevelCase::~TextureLevelCase (void) { deinit(); } void TextureLevelCase::init (void) { if (!isCoreTextureTarget(m_target, m_context.getRenderContext().getType())) { const char* const targetExtension = getTextureTargetExtension(m_target); if (!m_context.getContextInfo().isExtensionSupported(targetExtension)) throw tcu::NotSupportedError("Test requires " + std::string(targetExtension) + " extension"); } generateTestIterations(m_iterations); for (int iterationNdx = 0; iterationNdx < (int)m_iterations.size(); ++iterationNdx) DE_ASSERT(m_iterations[iterationNdx].bindTarget == m_target); } void TextureLevelCase::deinit (void) { if (m_texture) { m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture); m_texture = 0; } if (m_texBuffer) { m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texBuffer); m_texBuffer = 0; } } void TextureLevelCase::getFormatSamples (glw::GLenum internalFormat, std::vector& samples) { const glw::Functions gl = m_context.getRenderContext().getFunctions(); int sampleCount = -1; if (!isMultisampleTarget(m_target)) return; gl.getInternalformativ(m_target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount); if (sampleCount < 0) throw tcu::TestError("internal format query failed"); samples.resize(sampleCount); if (sampleCount > 0) { gl.getInternalformativ(m_target, internalFormat, GL_SAMPLES, sampleCount, &samples[0]); GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples"); } } TextureLevelCase::IterateResult TextureLevelCase::iterate (void) { const bool result = testConfig(m_iterations[m_iteration]); if (!result) { m_failedIterations.push_back(m_iteration); m_allIterationsOk = false; } if (++m_iteration < (int)m_iterations.size()) return CONTINUE; if (m_allIterationsOk) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else { tcu::MessageBuilder msg(&m_testCtx.getLog()); msg << "Following iteration(s) failed: "; for (int ndx = 0; ndx < (int)m_failedIterations.size(); ++ndx) { if (ndx) msg << ", "; msg << (m_failedIterations[ndx] + 1); } msg << tcu::TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "One or more iterations failed"); } return STOP; } bool TextureLevelCase::testConfig (const TextureGenerationSpec& spec) { const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration", std::string() + "Iteration " + de::toString(m_iteration+1) + "/" + de::toString((int)m_iterations.size()) + " - " + spec.description); glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); bool result; gl.enableLogging(true); gl.glGenTextures(1, &m_texture); gl.glBindTexture(spec.bindTarget, m_texture); GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen tex"); // Set the state applyTextureGenerationSpec(gl, spec, m_texBuffer); // Verify the state result = checkTextureState(gl, spec); gl.glDeleteTextures(1, &m_texture); m_texture = 0; if (m_texBuffer) { gl.glDeleteBuffers(1, &m_texBuffer); m_texture = 0; } return result; } /*--------------------------------------------------------------------*//*! * \brief Test texture target *//*--------------------------------------------------------------------*/ class TextureLevelCommonCase : public TextureLevelCase { public: TextureLevelCommonCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type); protected: virtual void generateTestIterations (std::vector& iterations); }; TextureLevelCommonCase::TextureLevelCommonCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCase(ctx, name, desc, target, type) { } void TextureLevelCommonCase::generateTestIterations (std::vector& iterations) { const glw::GLenum internalFormat = GL_RGBA8; int maxSamples; std::vector samples; getFormatSamples(internalFormat, samples); if (samples.empty()) maxSamples = -1; else maxSamples = samples[0]; generateColorTextureGenerationGroup(iterations, m_target, maxSamples, internalFormat); } class TextureLevelSampleCase : public TextureLevelCommonCase { public: TextureLevelSampleCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCommonCase(ctx, name, desc, target, type) { } private: bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { const int queryLevel = (spec.levels.empty()) ? (0) : (spec.levels[0].level); const int refValue = (spec.levels.empty()) ? (0) : (spec.sampleCount); return verifyTextureLevelParameterGreaterOrEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_SAMPLES, refValue, m_type); } }; class TextureLevelFixedSamplesCase : public TextureLevelCommonCase { public: TextureLevelFixedSamplesCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCommonCase(ctx, name, desc, target, type) { } private: bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { const int queryLevel = (spec.levels.empty()) ? (0) : (spec.levels[0].level); const int refValue = (spec.levels.empty()) ? (1) : ((spec.fixedSamplePos) ? (1) : (0)); return verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_FIXED_SAMPLE_LOCATIONS, refValue, m_type); } }; class TextureLevelWidthCase : public TextureLevelCommonCase { public: TextureLevelWidthCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCommonCase(ctx, name, desc, target, type) { } private: bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { const int initialValue = 0; bool allOk = true; if (spec.levels.empty()) { const int queryLevel = 0; const int refValue = initialValue; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_WIDTH, refValue, m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = spec.levels[levelNdx].width; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_WIDTH, refValue, m_type); } } return allOk; } }; class TextureLevelHeightCase : public TextureLevelCommonCase { public: TextureLevelHeightCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCommonCase(ctx, name, desc, target, type) { } private: bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { const int initialValue = 0; bool allOk = true; if (spec.levels.empty()) { const int queryLevel = 0; const int refValue = initialValue; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_HEIGHT, refValue, m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = spec.levels[levelNdx].height; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_HEIGHT, refValue, m_type); } } return allOk; } }; class TextureLevelDepthCase : public TextureLevelCommonCase { public: TextureLevelDepthCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCommonCase(ctx, name, desc, target, type) { } private: bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { const int initialValue = 0; bool allOk = true; if (spec.levels.empty()) { const int queryLevel = 0; const int refValue = initialValue; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_DEPTH, refValue, m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = spec.levels[levelNdx].depth; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_DEPTH, refValue, m_type); } } return allOk; } }; class TextureLevelInternalFormatCase : public TextureLevelCase { public: TextureLevelInternalFormatCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCase(ctx, name, desc, target, type) { } private: void generateTestIterations (std::vector& iterations) { generateInternalFormatTextureGenerationGroup(iterations, m_target); } bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { const int queryLevel = 0; const int initialValues[2] = { GL_RGBA, GL_R8 }; allOk &= verifyTextureLevelParameterInternalFormatAnyOf(gl, spec.queryTarget, queryLevel, GL_TEXTURE_INTERNAL_FORMAT, initialValues, DE_LENGTH_OF_ARRAY(initialValues), m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = spec.levels[levelNdx].internalFormat; allOk &= verifyTextureLevelParameterInternalFormatEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_INTERNAL_FORMAT, refValue, m_type); } } return allOk; } }; class TextureLevelSizeCase : public TextureLevelCase { public: TextureLevelSizeCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type, glw::GLenum pname); private: void generateTestIterations (std::vector& iterations); bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec); int getMinimumComponentResolution (glw::GLenum internalFormat); const glw::GLenum m_pname; }; TextureLevelSizeCase::TextureLevelSizeCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type, glw::GLenum pname) : TextureLevelCase (ctx, name, desc, target, type) , m_pname (pname) { } void TextureLevelSizeCase::generateTestIterations (std::vector& iterations) { generateInternalFormatTextureGenerationGroup(iterations, m_target); } bool TextureLevelSizeCase::checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, m_pname, 0, m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = getMinimumComponentResolution(spec.levels[levelNdx].internalFormat); allOk &= verifyTextureLevelParameterGreaterOrEqual(gl, spec.queryTarget, queryLevel, m_pname, refValue, m_type); } } return allOk; } int TextureLevelSizeCase::getMinimumComponentResolution (glw::GLenum internalFormat) { const tcu::TextureFormat format = glu::mapGLInternalFormat(internalFormat); const tcu::IVec4 channelBitDepth = tcu::getTextureFormatBitDepth(format); switch (m_pname) { case GL_TEXTURE_RED_SIZE: if (format.order == tcu::TextureFormat::R || format.order == tcu::TextureFormat::RG || format.order == tcu::TextureFormat::RGB || format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGB || format.order == tcu::TextureFormat::sRGBA) return channelBitDepth[0]; else return 0; case GL_TEXTURE_GREEN_SIZE: if (format.order == tcu::TextureFormat::RG || format.order == tcu::TextureFormat::RGB || format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGB || format.order == tcu::TextureFormat::sRGBA) return channelBitDepth[1]; else return 0; case GL_TEXTURE_BLUE_SIZE: if (format.order == tcu::TextureFormat::RGB || format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGB || format.order == tcu::TextureFormat::sRGBA) return channelBitDepth[2]; else return 0; case GL_TEXTURE_ALPHA_SIZE: if (format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGBA) return channelBitDepth[3]; else return 0; case GL_TEXTURE_DEPTH_SIZE: if (format.order == tcu::TextureFormat::D || format.order == tcu::TextureFormat::DS) return channelBitDepth[0]; else return 0; case GL_TEXTURE_STENCIL_SIZE: if (format.order == tcu::TextureFormat::DS) return channelBitDepth[3]; else return 0; case GL_TEXTURE_SHARED_SIZE: if (internalFormat == GL_RGB9_E5) return 5; else return 0; default: DE_ASSERT(DE_FALSE); return 0; } } class TextureLevelTypeCase : public TextureLevelCase { public: TextureLevelTypeCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type, glw::GLenum pname); private: void generateTestIterations (std::vector& iterations); bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec); int getComponentType (glw::GLenum internalFormat); const glw::GLenum m_pname; }; TextureLevelTypeCase::TextureLevelTypeCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type, glw::GLenum pname) : TextureLevelCase (ctx, name, desc, target, type) , m_pname (pname) { } void TextureLevelTypeCase::generateTestIterations (std::vector& iterations) { generateInternalFormatTextureGenerationGroup(iterations, m_target); } bool TextureLevelTypeCase::checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, m_pname, GL_NONE, m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = getComponentType(spec.levels[levelNdx].internalFormat); allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, m_pname, refValue, m_type); } } return allOk; } int TextureLevelTypeCase::getComponentType (glw::GLenum internalFormat) { const tcu::TextureFormat format = glu::mapGLInternalFormat(internalFormat); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); glw::GLenum channelType = GL_NONE; // depth-stencil special cases if (format.type == tcu::TextureFormat::UNSIGNED_INT_24_8) { if (m_pname == GL_TEXTURE_DEPTH_TYPE) return GL_UNSIGNED_NORMALIZED; else return GL_NONE; } else if (format.type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV) { if (m_pname == GL_TEXTURE_DEPTH_TYPE) return GL_FLOAT; else return GL_NONE; } else { switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: channelType = GL_SIGNED_NORMALIZED; break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: channelType = GL_UNSIGNED_NORMALIZED; break; case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: channelType = GL_INT; break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: channelType = GL_UNSIGNED_INT; break; case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: channelType = GL_FLOAT; break; default: DE_ASSERT(DE_FALSE); } } switch (m_pname) { case GL_TEXTURE_RED_TYPE: if (format.order == tcu::TextureFormat::R || format.order == tcu::TextureFormat::RG || format.order == tcu::TextureFormat::RGB || format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGB || format.order == tcu::TextureFormat::sRGBA) return channelType; else return GL_NONE; case GL_TEXTURE_GREEN_TYPE: if (format.order == tcu::TextureFormat::RG || format.order == tcu::TextureFormat::RGB || format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGB || format.order == tcu::TextureFormat::sRGBA) return channelType; else return GL_NONE; case GL_TEXTURE_BLUE_TYPE: if (format.order == tcu::TextureFormat::RGB || format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGB || format.order == tcu::TextureFormat::sRGBA) return channelType; else return GL_NONE; case GL_TEXTURE_ALPHA_TYPE: if (format.order == tcu::TextureFormat::RGBA || format.order == tcu::TextureFormat::BGRA || format.order == tcu::TextureFormat::ARGB || format.order == tcu::TextureFormat::sRGBA) return channelType; else return GL_NONE; case GL_TEXTURE_DEPTH_TYPE: if (format.order == tcu::TextureFormat::D || format.order == tcu::TextureFormat::DS) return channelType; else return GL_NONE; default: DE_ASSERT(DE_FALSE); return 0; } } class TextureLevelCompressedCase : public TextureLevelCase { public: TextureLevelCompressedCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCase(ctx, name, desc, target, type) { } private: void generateTestIterations (std::vector& iterations) { generateCompressedTextureGenerationGroup(iterations, m_target); } bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_COMPRESSED, 0, m_type); } else { for (int levelNdx = 0; levelNdx < (int)spec.levels.size(); ++levelNdx) { const int queryLevel = spec.levels[levelNdx].level; const int refValue = (spec.levels[levelNdx].compressed) ? (1) : (0); allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, queryLevel, GL_TEXTURE_COMPRESSED, refValue, m_type); } } return allOk; } }; static bool checkSupport(Context& ctx) { auto ctxType = ctx.getRenderContext().getType(); return contextSupports(ctxType, glu::ApiType::es(3, 2)) || contextSupports(ctxType, glu::ApiType::core(4, 5)) || ctx.getContextInfo().isExtensionSupported("GL_EXT_texture_buffer"); } class TextureLevelBufferDataStoreCase : public TextureLevelCase { public: TextureLevelBufferDataStoreCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCase(ctx, name, desc, target, type) { } private: void init (void) { if (!checkSupport(m_context)) throw tcu::NotSupportedError("Test requires GL_EXT_texture_buffer extension"); TextureLevelCase::init(); } void generateTestIterations (std::vector& iterations) { generateTextureBufferGenerationGroup(iterations, m_target); } bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_BUFFER_DATA_STORE_BINDING, 0, m_type); } else { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_BUFFER_DATA_STORE_BINDING, m_texBuffer, m_type); } return allOk; } }; class TextureLevelBufferDataOffsetCase : public TextureLevelCase { public: TextureLevelBufferDataOffsetCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCase(ctx, name, desc, target, type) { } private: void init (void) { if (!checkSupport(m_context)) throw tcu::NotSupportedError("Test requires GL_EXT_texture_buffer extension"); TextureLevelCase::init(); } void generateTestIterations (std::vector& iterations) { generateTextureBufferGenerationGroup(iterations, m_target); } bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_BUFFER_OFFSET, 0, m_type); } else { const int refValue = spec.texBufferDataOffset; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_BUFFER_OFFSET, refValue, m_type); } return allOk; } }; class TextureLevelBufferDataSizeCase : public TextureLevelCase { public: TextureLevelBufferDataSizeCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, QueryType type) : TextureLevelCase(ctx, name, desc, target, type) { } private: void init (void) { if (!checkSupport(m_context)) throw tcu::NotSupportedError("Test requires GL_EXT_texture_buffer extension"); TextureLevelCase::init(); } void generateTestIterations (std::vector& iterations) { generateTextureBufferGenerationGroup(iterations, m_target); } bool checkTextureState (glu::CallLogWrapper& gl, const TextureGenerationSpec& spec) { bool allOk = true; if (spec.levels.empty()) { allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_BUFFER_SIZE, 0, m_type); } else { const int refValue = spec.texBufferDataSize; allOk &= verifyTextureLevelParameterEqual(gl, spec.queryTarget, 0, GL_TEXTURE_BUFFER_SIZE, refValue, m_type); } return allOk; } }; } // anonymous static const char* getVerifierSuffix (QueryType type) { switch (type) { case QUERY_TEXTURE_LEVEL_FLOAT: return "_float"; case QUERY_TEXTURE_LEVEL_INTEGER: return "_integer"; default: DE_ASSERT(DE_FALSE); return DE_NULL; } } TextureLevelStateQueryTests::TextureLevelStateQueryTests (Context& context) : TestCaseGroup(context, "texture_level", "GetTexLevelParameter tests") { } TextureLevelStateQueryTests::~TextureLevelStateQueryTests (void) { } void TextureLevelStateQueryTests::init (void) { static const QueryType verifiers[] = { QUERY_TEXTURE_LEVEL_INTEGER, QUERY_TEXTURE_LEVEL_FLOAT, }; #define FOR_EACH_VERIFIER(X) \ for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx) \ { \ const std::string verifierSuffix = getVerifierSuffix(verifiers[verifierNdx]); \ const QueryType verifier = verifiers[verifierNdx]; \ targetGroup->addChild(X); \ } static const struct { const char* name; glw::GLenum target; } textureTargets[] = { { "texture_2d", GL_TEXTURE_2D, }, { "texture_3d", GL_TEXTURE_3D, }, { "texture_2d_array", GL_TEXTURE_2D_ARRAY, }, { "texture_cube_map", GL_TEXTURE_CUBE_MAP, }, { "texture_2d_multisample", GL_TEXTURE_2D_MULTISAMPLE, }, { "texture_2d_multisample_array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, }, // GL_OES_texture_storage_multisample_2d_array { "texture_buffer", GL_TEXTURE_BUFFER, }, // GL_EXT_texture_buffer { "texture_cube_array", GL_TEXTURE_CUBE_MAP_ARRAY, }, // GL_EXT_texture_cube_map_array }; for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(textureTargets); ++targetNdx) { tcu::TestCaseGroup* const targetGroup = new tcu::TestCaseGroup(m_testCtx, textureTargets[targetNdx].name, textureTargets[targetNdx].name); addChild(targetGroup); FOR_EACH_VERIFIER(new TextureLevelSampleCase (m_context, ("samples" + verifierSuffix).c_str(), "Verify TEXTURE_SAMPLES", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelFixedSamplesCase (m_context, ("fixed_sample_locations" + verifierSuffix).c_str(), "Verify TEXTURE_FIXED_SAMPLE_LOCATIONS", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelWidthCase (m_context, ("width" + verifierSuffix).c_str(), "Verify TEXTURE_WIDTH", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelHeightCase (m_context, ("height" + verifierSuffix).c_str(), "Verify TEXTURE_HEIGHT", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelDepthCase (m_context, ("depth" + verifierSuffix).c_str(), "Verify TEXTURE_DEPTH", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelInternalFormatCase (m_context, ("internal_format" + verifierSuffix).c_str(), "Verify TEXTURE_INTERNAL_FORMAT", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("red_size" + verifierSuffix).c_str(), "Verify TEXTURE_RED_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_RED_SIZE)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("green_size" + verifierSuffix).c_str(), "Verify TEXTURE_GREEN_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_GREEN_SIZE)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("blue_size" + verifierSuffix).c_str(), "Verify TEXTURE_BLUE_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_BLUE_SIZE)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("alpha_size" + verifierSuffix).c_str(), "Verify TEXTURE_ALPHA_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_ALPHA_SIZE)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("depth_size" + verifierSuffix).c_str(), "Verify TEXTURE_DEPTH_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_DEPTH_SIZE)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("stencil_size" + verifierSuffix).c_str(), "Verify TEXTURE_STENCIL_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_STENCIL_SIZE)); FOR_EACH_VERIFIER(new TextureLevelSizeCase (m_context, ("shared_size" + verifierSuffix).c_str(), "Verify TEXTURE_SHARED_SIZE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_SHARED_SIZE)); FOR_EACH_VERIFIER(new TextureLevelTypeCase (m_context, ("red_type" + verifierSuffix).c_str(), "Verify TEXTURE_RED_TYPE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_RED_TYPE)); FOR_EACH_VERIFIER(new TextureLevelTypeCase (m_context, ("green_type" + verifierSuffix).c_str(), "Verify TEXTURE_GREEN_TYPE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_GREEN_TYPE)); FOR_EACH_VERIFIER(new TextureLevelTypeCase (m_context, ("blue_type" + verifierSuffix).c_str(), "Verify TEXTURE_BLUE_TYPE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_BLUE_TYPE)); FOR_EACH_VERIFIER(new TextureLevelTypeCase (m_context, ("alpha_type" + verifierSuffix).c_str(), "Verify TEXTURE_ALPHA_TYPE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_ALPHA_TYPE)); FOR_EACH_VERIFIER(new TextureLevelTypeCase (m_context, ("depth_type" + verifierSuffix).c_str(), "Verify TEXTURE_DEPTH_TYPE", textureTargets[targetNdx].target, verifier, GL_TEXTURE_DEPTH_TYPE)); FOR_EACH_VERIFIER(new TextureLevelCompressedCase (m_context, ("compressed" + verifierSuffix).c_str(), "Verify TEXTURE_COMPRESSED", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelBufferDataStoreCase (m_context, ("buffer_data_store_binding" + verifierSuffix).c_str(), "Verify TEXTURE_BUFFER_DATA_STORE_BINDING", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelBufferDataOffsetCase (m_context, ("buffer_offset" + verifierSuffix).c_str(), "Verify TEXTURE_BUFFER_OFFSET", textureTargets[targetNdx].target, verifier)); FOR_EACH_VERIFIER(new TextureLevelBufferDataSizeCase (m_context, ("buffer_size" + verifierSuffix).c_str(), "Verify TEXTURE_BUFFER_SIZE", textureTargets[targetNdx].target, verifier)); } #undef FOR_EACH_VERIFIER } } // Functional } // gles31 } // deqp