/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2014-2016 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 * \brief */ /*-------------------------------------------------------------------*/ /*! * \file esextcTextureCubeMapArrayGenerateMipMap.cpp * \brief texture_cube_map_array extenstion - glGenerateMipmap() (Test 7) */ /*-------------------------------------------------------------------*/ #include "esextcTextureCubeMapArrayGenerateMipMap.hpp" #include "gluContextInfo.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "tcuTestLog.hpp" #include #include #include namespace glcts { /* Defines two pattern colors for each layer-face */ const unsigned char TextureCubeMapArrayGenerateMipMapFilterable::m_layer_face_data [m_n_max_faces][m_n_colors_per_layer_face][m_n_components] = { /* Color 1 --- Color 2 */ { { 0, 0, 0, 0 }, { 255, 255, 255, 255 } }, /* Layer-face 0 */ { { 255, 0, 0, 0 }, { 0, 255, 255, 255 } }, /* Layer-face 1 */ { { 0, 255, 0, 0 }, { 255, 0, 255, 255 } }, /* Layer-face 2 */ { { 0, 0, 255, 0 }, { 255, 255, 0, 255 } }, /* Layer-face 3 */ { { 0, 0, 0, 255 }, { 255, 255, 255, 0 } }, /* Layer-face 4 */ { { 255, 255, 0, 0 }, { 0, 0, 255, 255 } }, /* Layer-face 5 */ { { 255, 0, 255, 0 }, { 0, 255, 0, 255 } }, /* Layer-face 6 */ { { 255, 0, 0, 255 }, { 0, 255, 255, 0 } }, /* Layer-face 7 */ { { 0, 255, 255, 0 }, { 255, 0, 0, 255 } }, /* Layer-face 8 */ { { 0, 255, 0, 255 }, { 255, 0, 255, 0 } }, /* Layer-face 9 */ { { 255, 255, 255, 0 }, { 0, 0, 0, 255 } }, /* Layer-face 10 */ { { 255, 255, 0, 255 }, { 0, 0, 255, 0 } }, /* Layer-face 11 */ { { 255, 255, 255, 255 }, { 0, 0, 0, 0 } }, /* Layer-face 12 */ { { 0, 0, 0, 255 }, { 255, 0, 0, 0 } }, /* Layer-face 13 */ { { 0, 0, 0, 255 }, { 255, 255, 0, 0 } }, /* Layer-face 14 */ { { 0, 0, 255, 0 }, { 255, 255, 255, 0 } }, /* Layer-face 15 */ { { 0, 255, 0, 0 }, { 255, 255, 255, 255 } }, /* Layer-face 16 */ { { 255, 0, 0, 0 }, { 255, 0, 255, 255 } } /* Layer-face 17 */ }; /** Retrieves maximum amount of levels that should be defined for * a texture of user-provided dimensions. * * @param width Width of the texture in question. * @param height Height of the texture in question. * * @return Requested value. **/ static int getAmountOfLevelsForTexture(int width, int height) { return (int)floor(log((float)(de::max(width, height))) / log(2.0f)) + 1; } /** Constructor * * @param context Test context; * @param name Test case's name; * @param description Test case's description; * @param storageType Precises whether texture objects used by this * test instance should be created as immutable or * mutable objects. **/ TextureCubeMapArrayGenerateMipMapFilterable::TextureCubeMapArrayGenerateMipMapFilterable(Context& context, const ExtParameters& extParams, const char* name, const char* description, STORAGE_TYPE storageType) : TestCaseBase(context, extParams, name, description) , m_fbo_id(0) , m_storage_type(storageType) , m_reference_data_ptr(DE_NULL) , m_rendered_data_ptr(DE_NULL) { /* Nothing to be done here */ } /** Deinitialize test case **/ void TextureCubeMapArrayGenerateMipMapFilterable::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Reset texture and FBO bindings */ gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0); gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0); /* Release any ES objects that may have been created. */ if (m_fbo_id != 0) { gl.deleteFramebuffers(1, &m_fbo_id); m_fbo_id = 0; } for (unsigned int i = 0; i < m_storage_configs.size(); ++i) { if (m_storage_configs[i].m_to_id != 0) { gl.deleteTextures(1, &m_storage_configs[i].m_to_id); m_storage_configs[i].m_to_id = 0; } } /* Release buffers the test may have allocated */ if (m_reference_data_ptr != DE_NULL) { delete[] m_reference_data_ptr; m_reference_data_ptr = DE_NULL; } if (m_rendered_data_ptr != DE_NULL) { delete[] m_rendered_data_ptr; m_rendered_data_ptr = DE_NULL; } /* Restore pixel pack/unpack settings */ gl.pixelStorei(GL_PACK_ALIGNMENT, 4); gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); /* Call base class' deinitialization routine. */ TestCaseBase::deinit(); } /** Fills user-provided buffer with expected pixel data for user-specified * layer index. * * @param n_layer Layer index to return expected data for. * @param data Pointer to a buffer that will be filled with * result data. Must not be NULL. * @param width Render-target width. * @param height Render-target height. */ void TextureCubeMapArrayGenerateMipMapFilterable::generateTestData(int n_layer, unsigned char* data, int width, int height) { DE_ASSERT(data != DE_NULL); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { for (int n_component = 0; n_component < m_n_components; ++n_component) { const unsigned int pixel_size = m_n_components; unsigned char* result_ptr = data + ((y * width + x) * pixel_size + n_component); unsigned int n_color = ((x % m_n_colors_per_layer_face) + y) % m_n_colors_per_layer_face; *result_ptr = m_layer_face_data[n_layer][n_color][n_component]; } } } } /** Initialize test case **/ void TextureCubeMapArrayGenerateMipMapFilterable::init() { /* Base class initialization */ TestCaseBase::init(); /* Check if texture_cube_map_array extension is supported */ if (!m_is_texture_cube_map_array_supported) { throw tcu::NotSupportedError(TEXTURE_CUBE_MAP_ARRAY_EXTENSION_NOT_SUPPORTED); } } /** Initializes all ES objects that will be used by the test */ void TextureCubeMapArrayGenerateMipMapFilterable::initTest() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Make sure the storage config container is empty */ m_storage_configs.clear(); /* Update pixel pack/unpack settings */ gl.pixelStorei(GL_PACK_ALIGNMENT, 1); gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call(s) failed"); /* Define following texture configurations * * [width x height x depth] * 1) 64 x 64 x 18; * 2) 117 x 117 x 6; * 3) 256 x 256 x 6; * 4) 173 x 173 x 12; * * We use GL_RGBA8 internal format in all cases. */ /* Resolution 64 x 64 x 18 */ StorageConfig storage_config_1; storage_config_1.m_width = 64; storage_config_1.m_height = 64; storage_config_1.m_depth = 18; storage_config_1.m_to_id = 0; storage_config_1.m_levels = getAmountOfLevelsForTexture(storage_config_1.m_width, storage_config_1.m_height); /* Resolution 117 x 117 x 6 */ StorageConfig storage_config_2; storage_config_2.m_width = 117; storage_config_2.m_height = 117; storage_config_2.m_depth = 6; storage_config_2.m_to_id = 0; storage_config_2.m_levels = getAmountOfLevelsForTexture(storage_config_2.m_width, storage_config_2.m_height); /* Resolution 256 x 256 x 6 */ StorageConfig storage_config_3; storage_config_3.m_width = 256; storage_config_3.m_height = 256; storage_config_3.m_depth = 6; storage_config_3.m_to_id = 0; storage_config_3.m_levels = getAmountOfLevelsForTexture(storage_config_3.m_width, storage_config_3.m_height); /* Resolution 173 x 173 x 12 */ StorageConfig storage_config_4; storage_config_4.m_width = 173; storage_config_4.m_height = 173; storage_config_4.m_depth = 12; storage_config_4.m_to_id = 0; storage_config_4.m_levels = getAmountOfLevelsForTexture(storage_config_4.m_width, storage_config_4.m_height); m_storage_configs.push_back(storage_config_1); m_storage_configs.push_back(storage_config_2); m_storage_configs.push_back(storage_config_3); m_storage_configs.push_back(storage_config_4); /* Generate and configure a texture object for each storage config. */ for (unsigned int n_storage_config = 0; n_storage_config < m_storage_configs.size(); n_storage_config++) { StorageConfig& config = m_storage_configs[n_storage_config]; gl.genTextures(1, &config.m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed"); gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, config.m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call(s) failed"); if (m_storage_type == ST_MUTABLE) { gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, /* level */ GL_RGBA8, config.m_width, config.m_height, config.m_depth, 0, /* border */ GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage3D() call failed"); } else { DE_ASSERT(m_storage_type == ST_IMMUTABLE); gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, config.m_levels, GL_RGBA8, config.m_width, config.m_height, config.m_depth); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed"); } } /* for (all storage configs) */ /* Generate a frame-buffer object */ gl.genFramebuffers(1, &m_fbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed"); } /** Executes the test. * * Note the function throws exception should an error occur! * * @return Always STOP. **/ tcu::TestCase::IterateResult TextureCubeMapArrayGenerateMipMapFilterable::iterate() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Initialize ES objects we will need to run the test */ initTest(); /* Iterate through all configuration descriptors */ unsigned int n_storage_config = 0; for (std::vector::const_iterator storage_config_iterator = m_storage_configs.begin(); storage_config_iterator != m_storage_configs.end(); storage_config_iterator++, n_storage_config++) { const StorageConfig& storage_config = *storage_config_iterator; gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, storage_config.m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); /* Fill each base layer-face with pattern data */ for (unsigned int n_layer_face = 0; n_layer_face < storage_config.m_depth; ++n_layer_face) { /* Allocate buffer we will use to store the layer data */ const int data_size = static_cast(storage_config.m_width * storage_config.m_height * m_n_components * sizeof(unsigned char)); unsigned char* data_ptr = new unsigned char[data_size]; if (data_ptr == DE_NULL) { TCU_FAIL("Out of memory"); } generateTestData(n_layer_face, data_ptr, storage_config.m_width, storage_config.m_height); /* Fill base texture-layer Texture */ gl.texSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, /* level */ 0, /* xoffset */ 0, /* yoffset */ n_layer_face, /* zoffset */ storage_config.m_width, storage_config.m_height, 1, /* depth */ GL_RGBA, GL_UNSIGNED_BYTE, data_ptr); /* Release the data buffer */ delete[] data_ptr; data_ptr = DE_NULL; /* Make sure the call was successful */ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage3D() call failed"); } /* Generate mip-maps */ gl.generateMipmap(GL_TEXTURE_CUBE_MAP_ARRAY); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap() call failed"); /* Attach a FBO to GL_READ_FRAMEBUFFER binding point. */ gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed"); /* Allocate buffers to hold reference & rendered data */ unsigned char last_level_data_buffer[m_n_components] = { 0 }; const unsigned int size = static_cast(storage_config.m_width * storage_config.m_height * m_n_components * sizeof(unsigned char)); m_reference_data_ptr = new unsigned char[size]; m_rendered_data_ptr = new unsigned char[size]; if (m_reference_data_ptr == DE_NULL || m_rendered_data_ptr == DE_NULL) { TCU_FAIL("Out of memory"); } /* Verify correctness of layer-face data */ for (unsigned int n_layer_face = 0; n_layer_face < storage_config.m_depth; ++n_layer_face) { /* Generate reference data */ generateTestData(n_layer_face, m_reference_data_ptr, storage_config.m_width, storage_config.m_height); /* Attach iteration-specific base layer-face to the read frame-buffer */ gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, storage_config.m_to_id, 0, /* level */ n_layer_face); GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTextureLayer() call failed."); /* Read the layer-face data */ gl.readPixels(0, /* x */ 0, /* y */ storage_config.m_width, storage_config.m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_rendered_data_ptr); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed."); /* Make sure the base layer-face contents reported with the call is as was uploaded */ const unsigned int base_layer_data_size = static_cast( storage_config.m_width * storage_config.m_height * m_n_components * sizeof(unsigned char)); if (memcmp(m_reference_data_ptr, m_rendered_data_ptr, base_layer_data_size)) { m_testCtx.getLog() << tcu::TestLog::Message << "Data stored in base layer mip-map for storage config [" << n_storage_config << "]" "and layer-face index [" << n_layer_face << "]" " is different than was uploaded" << tcu::TestLog::EndMessage; TCU_FAIL("Invalid data found for base layer mip-map"); } /* Update the read framebuffer's color attachment to read from * the last mip-map available for currently processed layer-face */ gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, storage_config.m_to_id, /* texture */ storage_config.m_levels - 1, /* level */ n_layer_face); /* layer */ GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTextureLayer() call failed."); /* Read the data */ gl.readPixels(0, /* x */ 0, /* y */ 1, /* width */ 1, /* height */ GL_RGBA, GL_UNSIGNED_BYTE, last_level_data_buffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed"); /* Make sure that the data read from the last layer is not equal to either * of the pattern colors used for the layer-face */ for (int n_pattern_color = 0; n_pattern_color < m_n_colors_per_layer_face; ++n_pattern_color) { if (!memcmp(m_layer_face_data[n_layer_face][n_pattern_color], last_level_data_buffer, m_n_components * sizeof(unsigned char))) { m_testCtx.getLog() << tcu::TestLog::Message << "Texel stored in layer-face's smallest mip-map for storage config [" << n_storage_config << "]" "and layer-face index [" << n_layer_face << "]" "describes one of the colors used for the pattern used in base mip-map, which is invalid." << tcu::TestLog::EndMessage; TCU_FAIL("Invalid color found in the layer-face's smallest mip-map"); } } /* for (all pattern colors) */ } /* for (all layer-faces) */ /* Release the buffers we allocated specifically for currently processed * storage config. */ if (m_reference_data_ptr != DE_NULL) { delete[] m_reference_data_ptr; m_reference_data_ptr = DE_NULL; } if (m_rendered_data_ptr != DE_NULL) { delete[] m_rendered_data_ptr; m_rendered_data_ptr = DE_NULL; } } /* for (all storage configs) */ /* Test has passed */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } /** Constructor * * @param context Test context * @param name Test case's name * @param description Test case's description * @param storageType Precises whether texture objects used by this * test instance should be created as immutable or * mutable objects. **/ TextureCubeMapArrayGenerateMipMapNonFilterable::TextureCubeMapArrayGenerateMipMapNonFilterable( Context& context, const ExtParameters& extParams, const char* name, const char* description, STORAGE_TYPE storageType) : TestCaseBase(context, extParams, name, description), m_storage_type(storageType) { /* Nothing to be done here */ } /** Deinitialize test case **/ void TextureCubeMapArrayGenerateMipMapNonFilterable::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Restore default bindings */ gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0); /* Restore default pixel pack/unpack settings */ gl.pixelStorei(GL_PACK_ALIGNMENT, 4); gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); /* Delete all textures the test may have created. */ for (unsigned int n_storage_config = 0; n_storage_config < m_non_filterable_texture_configs.size(); ++n_storage_config) { if (m_non_filterable_texture_configs[n_storage_config].m_to_id != 0) { gl.deleteTextures(1, &m_non_filterable_texture_configs[n_storage_config].m_to_id); m_non_filterable_texture_configs[n_storage_config].m_to_id = 0; } } /* Call base class' deinit() implementation */ TestCaseBase::deinit(); } /** Initialize test case **/ void TextureCubeMapArrayGenerateMipMapNonFilterable::init() { /* Base class initialization */ TestCaseBase::init(); if (!glu::isContextTypeES(m_context.getRenderContext().getType())) { throw tcu::NotSupportedError("The test can be run only in ES context"); } /* Check if texture_cube_map_array extension is supported */ if (!m_is_texture_cube_map_array_supported) { throw tcu::NotSupportedError(TEXTURE_CUBE_MAP_ARRAY_EXTENSION_NOT_SUPPORTED); } } /** Initializes all ES objects used by the test **/ void TextureCubeMapArrayGenerateMipMapNonFilterable::initTest() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Make sure no configs are already in place */ m_non_filterable_texture_configs.clear(); /* Update pixel pack/unpack settings */ gl.pixelStorei(GL_PACK_ALIGNMENT, 1); gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call(s) failed"); /* Define a number of storage configurations, all using GL_RGBA32I * internalformat: * * [width x height x depth] * 1) 64 x 64 x 18; * 2) 117 x 117 x 6; * 3) 256 x 256 x 6; * 4) 173 x 173 x 12; */ /* Size 64 x 64 x 18 */ StorageConfig storage_config1; storage_config1.m_width = 64; storage_config1.m_height = 64; storage_config1.m_depth = 18; storage_config1.m_to_id = 0; storage_config1.m_levels = getAmountOfLevelsForTexture(storage_config1.m_width, storage_config1.m_height); /* Size 117 x 117 x 6 */ StorageConfig storage_config2; storage_config2.m_width = 117; storage_config2.m_height = 117; storage_config2.m_depth = 6; storage_config2.m_to_id = 0; storage_config2.m_levels = getAmountOfLevelsForTexture(storage_config2.m_width, storage_config2.m_height); /* Size 256 x 256 x 6 */ StorageConfig storage_config3; storage_config3.m_width = 256; storage_config3.m_height = 256; storage_config3.m_depth = 6; storage_config3.m_to_id = 0; storage_config3.m_levels = getAmountOfLevelsForTexture(storage_config3.m_width, storage_config3.m_height); /* Size 173 x 173 x 12 */ StorageConfig storage_config4; storage_config4.m_width = 173; storage_config4.m_height = 173; storage_config4.m_depth = 12; storage_config4.m_to_id = 0; storage_config4.m_levels = getAmountOfLevelsForTexture(storage_config4.m_width, storage_config4.m_height); m_non_filterable_texture_configs.push_back(storage_config1); m_non_filterable_texture_configs.push_back(storage_config2); m_non_filterable_texture_configs.push_back(storage_config3); m_non_filterable_texture_configs.push_back(storage_config4); /* Generate and configure a texture object for each storage config. */ for (std::vector::iterator storage_config_iterator = m_non_filterable_texture_configs.begin(); storage_config_iterator != m_non_filterable_texture_configs.end(); storage_config_iterator++) { StorageConfig& storage_config = *storage_config_iterator; gl.genTextures(1, &storage_config.m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, storage_config.m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call(s) failed."); /* Initialize texture storage. */ if (m_storage_type == ST_MUTABLE) { gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, /* level */ GL_RGBA32I, storage_config.m_width, storage_config.m_height, storage_config.m_depth, 0, GL_RGBA_INTEGER, GL_INT, 0); /* data */ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage3D() call failed."); } else { gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, storage_config.m_levels, GL_RGBA32I, storage_config.m_width, storage_config.m_height, storage_config.m_depth); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed."); } } /* for (all storage configs) */ } /** Executes the test. * * Note the function throws exception should an error occur! * * @return Always STOP. **/ tcu::TestCase::IterateResult TextureCubeMapArrayGenerateMipMapNonFilterable::iterate() { /* Initialize ES objects used by the test */ initTest(); /* Verify that glGenerateMipmap() always throws GL_INVALID_OPERATION, if the * texture object the call would operate on uses non-filterable internalformat. */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); for (unsigned int n_storage_config = 0; n_storage_config < m_non_filterable_texture_configs.size(); ++n_storage_config) { gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_non_filterable_texture_configs[n_storage_config].m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); gl.generateMipmap(GL_TEXTURE_CUBE_MAP_ARRAY); /* What's the error code at this point? */ int error_code = gl.getError(); if (error_code != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "glGenerateMipmap() operating on an non-filterable internalformat " "did not report GL_INVALID_OPERATION as per spec but " << error_code << " instead." << tcu::TestLog::EndMessage; TCU_FAIL("Invalid error code reported for an invalid glGenerateMipmap() call."); } } /* for (all storage configs) */ /* The test has passed */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } } /* glcts */