| /*------------------------------------------------------------------------- |
| * 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 gl4cTextureViewTests.cpp |
| * \brief Implements conformance tests for "texture view" functionality. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cTextureViewTests.hpp" |
| #include "deFloat16.h" |
| #include "deMath.h" |
| #include "gluContextInfo.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuFloat.hpp" |
| #include "tcuTestLog.hpp" |
| #include <algorithm> |
| |
| /* Type definitions needed to handle GL_R11F_G11F_B10F internal format */ |
| typedef tcu::Float<deUint32, 5, 5, 15, 0> Float10; |
| typedef tcu::Float<deUint32, 5, 6, 15, 0> Float11; |
| |
| namespace gl4cts |
| { |
| using namespace TextureView; |
| |
| /** Stores internalformat->view class associations */ |
| const int internalformat_view_compatibility_array[] = { |
| /* [internalformat] [view class] */ |
| GL_RGBA32F, VIEW_CLASS_128_BITS, GL_RGBA32UI, VIEW_CLASS_128_BITS, GL_RGBA32I, VIEW_CLASS_128_BITS, GL_RGB32F, |
| VIEW_CLASS_96_BITS, GL_RGB32UI, VIEW_CLASS_96_BITS, GL_RGB32I, VIEW_CLASS_96_BITS, GL_RGBA16F, VIEW_CLASS_64_BITS, |
| GL_RG32F, VIEW_CLASS_64_BITS, GL_RGBA16UI, VIEW_CLASS_64_BITS, GL_RG32UI, VIEW_CLASS_64_BITS, GL_RGBA16I, |
| VIEW_CLASS_64_BITS, GL_RG32I, VIEW_CLASS_64_BITS, GL_RGBA16, VIEW_CLASS_64_BITS, GL_RGBA16_SNORM, |
| VIEW_CLASS_64_BITS, GL_RGB16, VIEW_CLASS_48_BITS, GL_RGB16_SNORM, VIEW_CLASS_48_BITS, GL_RGB16F, VIEW_CLASS_48_BITS, |
| GL_RGB16UI, VIEW_CLASS_48_BITS, GL_RGB16I, VIEW_CLASS_48_BITS, GL_RG16F, VIEW_CLASS_32_BITS, GL_R11F_G11F_B10F, |
| VIEW_CLASS_32_BITS, GL_R32F, VIEW_CLASS_32_BITS, GL_RGB10_A2UI, VIEW_CLASS_32_BITS, GL_RGBA8UI, VIEW_CLASS_32_BITS, |
| GL_RG16UI, VIEW_CLASS_32_BITS, GL_R32UI, VIEW_CLASS_32_BITS, GL_RGBA8I, VIEW_CLASS_32_BITS, GL_RG16I, |
| VIEW_CLASS_32_BITS, GL_R32I, VIEW_CLASS_32_BITS, GL_RGB10_A2, VIEW_CLASS_32_BITS, GL_RGBA8, VIEW_CLASS_32_BITS, |
| GL_RG16, VIEW_CLASS_32_BITS, GL_RGBA8_SNORM, VIEW_CLASS_32_BITS, GL_RG16_SNORM, VIEW_CLASS_32_BITS, GL_SRGB8_ALPHA8, |
| VIEW_CLASS_32_BITS, GL_RGB9_E5, VIEW_CLASS_32_BITS, GL_RGB8, VIEW_CLASS_24_BITS, GL_RGB8_SNORM, VIEW_CLASS_24_BITS, |
| GL_SRGB8, VIEW_CLASS_24_BITS, GL_RGB8UI, VIEW_CLASS_24_BITS, GL_RGB8I, VIEW_CLASS_24_BITS, GL_R16F, |
| VIEW_CLASS_16_BITS, GL_RG8UI, VIEW_CLASS_16_BITS, GL_R16UI, VIEW_CLASS_16_BITS, GL_RG8I, VIEW_CLASS_16_BITS, |
| GL_R16I, VIEW_CLASS_16_BITS, GL_RG8, VIEW_CLASS_16_BITS, GL_R16, VIEW_CLASS_16_BITS, GL_RG8_SNORM, |
| VIEW_CLASS_16_BITS, GL_R16_SNORM, VIEW_CLASS_16_BITS, GL_R8UI, VIEW_CLASS_8_BITS, GL_R8I, VIEW_CLASS_8_BITS, GL_R8, |
| VIEW_CLASS_8_BITS, GL_R8_SNORM, VIEW_CLASS_8_BITS, |
| |
| /* Compressed texture formats. */ |
| GL_COMPRESSED_RED_RGTC1, VIEW_CLASS_RGTC1_RED, GL_COMPRESSED_SIGNED_RED_RGTC1, VIEW_CLASS_RGTC1_RED, |
| GL_COMPRESSED_RG_RGTC2, VIEW_CLASS_RGTC2_RG, GL_COMPRESSED_SIGNED_RG_RGTC2, VIEW_CLASS_RGTC2_RG, |
| GL_COMPRESSED_RGBA_BPTC_UNORM, VIEW_CLASS_BPTC_UNORM, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, VIEW_CLASS_BPTC_UNORM, |
| GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, VIEW_CLASS_BPTC_FLOAT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, |
| VIEW_CLASS_BPTC_FLOAT |
| }; |
| |
| const int n_internalformat_view_compatibility_array_entries = |
| sizeof(internalformat_view_compatibility_array) / sizeof(internalformat_view_compatibility_array[0]); |
| |
| /** Stores all internalformats valid in OpenGL 4.x. Information whether particular internalformat |
| * can be considered supported can be retrieved by calling TextureViewTests::isInternalformatSupported() |
| * function. |
| */ |
| const glw::GLenum valid_gl_internalformats[] = { |
| /* Section 8.5.1 */ |
| GL_RGBA32F, /* >= GL 4.0 */ |
| GL_RGBA32I, /* >= GL 4.0 */ |
| GL_RGBA32UI, /* >= GL 4.0 */ |
| GL_RGBA16, /* >= GL 4.0 */ |
| GL_RGBA16F, /* >= GL 4.0 */ |
| GL_RGBA16I, /* >= GL 4.0 */ |
| GL_RGBA16UI, /* >= GL 4.0 */ |
| GL_RGBA8, /* >= GL 4.0 */ |
| GL_RGBA8I, /* >= GL 4.0 */ |
| GL_RGBA8UI, /* >= GL 4.0 */ |
| GL_SRGB8_ALPHA8, /* >= GL 4.0 */ |
| GL_RGB10_A2, /* >= GL 4.0 */ |
| GL_RGB10_A2UI, /* >= GL 4.0 */ |
| GL_RGB5_A1, /* >= GL 4.0 */ |
| GL_RGBA4, /* >= GL 4.0 */ |
| GL_R11F_G11F_B10F, /* >= GL 4.0 */ |
| GL_RGB565, /* >= GL 4.2 */ |
| GL_RG32F, /* >= GL 4.0 */ |
| GL_RG32I, /* >= GL 4.0 */ |
| GL_RG32UI, /* >= GL 4.0 */ |
| GL_RG16, /* >= GL 4.0 */ |
| GL_RG16F, /* >= GL 4.0 */ |
| GL_RG16I, /* >= GL 4.0 */ |
| GL_RG16UI, /* >= GL 4.0 */ |
| GL_RG8, /* >= GL 4.0 */ |
| GL_RG8I, /* >= GL 4.0 */ |
| GL_RG8UI, /* >= GL 4.0 */ |
| GL_R32F, /* >= GL 4.0 */ |
| GL_R32I, /* >= GL 4.0 */ |
| GL_R32UI, /* >= GL 4.0 */ |
| GL_R16F, /* >= GL 4.0 */ |
| GL_R16I, /* >= GL 4.0 */ |
| GL_R16UI, /* >= GL 4.0 */ |
| GL_R16, /* >= GL 4.0 */ |
| GL_R8, /* >= GL 4.0 */ |
| GL_R8I, /* >= GL 4.0 */ |
| GL_R8UI, /* >= GL 4.0 */ |
| GL_RGBA16_SNORM, /* >= GL 4.0 */ |
| GL_RGBA8_SNORM, /* >= GL 4.0 */ |
| GL_RGB32F, /* >= GL 4.0 */ |
| GL_RGB32I, /* >= GL 4.0 */ |
| GL_RGB32UI, /* >= GL 4.0 */ |
| GL_RGB16_SNORM, /* >= GL 4.0 */ |
| GL_RGB16F, /* >= GL 4.0 */ |
| GL_RGB16I, /* >= GL 4.0 */ |
| GL_RGB16UI, /* >= GL 4.0 */ |
| GL_RGB16, /* >= GL 4.0 */ |
| GL_RGB8_SNORM, /* >= GL 4.0 */ |
| GL_RGB8, /* >= GL 4.0 */ |
| GL_RGB8I, /* >= GL 4.0 */ |
| GL_RGB8UI, /* >= GL 4.0 */ |
| GL_SRGB8, /* >= GL 4.0 */ |
| GL_RGB9_E5, /* >= GL 4.0 */ |
| GL_RG16_SNORM, /* >= GL 4.0 */ |
| GL_RG8_SNORM, /* >= GL 4.0 */ |
| GL_R16_SNORM, /* >= GL 4.0 */ |
| GL_R8_SNORM, /* >= GL 4.0 */ |
| |
| GL_DEPTH_COMPONENT32F, /* >= GL 4.0 */ |
| GL_DEPTH_COMPONENT24, /* >= GL 4.0 */ |
| GL_DEPTH_COMPONENT16, /* >= GL 4.0 */ |
| |
| GL_DEPTH32F_STENCIL8, /* >= GL 4.0 */ |
| GL_DEPTH24_STENCIL8, /* >= GL 4.0 */ |
| |
| /* Table 8.14: generic compressed internalformats have been removed */ |
| GL_COMPRESSED_RED_RGTC1, /* >= GL 4.0 */ |
| GL_COMPRESSED_SIGNED_RED_RGTC1, /* >= GL 4.0 */ |
| GL_COMPRESSED_RG_RGTC2, /* >= GL 4.0 */ |
| GL_COMPRESSED_SIGNED_RG_RGTC2, /* >= GL 4.0 */ |
| GL_COMPRESSED_RGBA_BPTC_UNORM, /* >= GL 4.2 */ |
| GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, /* >= GL 4.2 */ |
| GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, /* >= GL 4.2 */ |
| GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, /* >= GL 4.2 */ |
| GL_COMPRESSED_RGB8_ETC2, /* >= GL 4.3 */ |
| GL_COMPRESSED_SRGB8_ETC2, /* >= GL 4.3 */ |
| GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, /* >= GL 4.3 */ |
| GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, /* >= GL 4.3 */ |
| GL_COMPRESSED_RGBA8_ETC2_EAC, /* >= GL 4.3 */ |
| GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, /* >= GL 4.3 */ |
| GL_COMPRESSED_R11_EAC, /* >= GL 4.3 */ |
| GL_COMPRESSED_SIGNED_R11_EAC, /* >= GL 4.3 */ |
| GL_COMPRESSED_RG11_EAC, /* >= GL 4.3 */ |
| GL_COMPRESSED_SIGNED_RG11_EAC, /* >= GL 4.3 */ |
| }; |
| |
| const int n_valid_gl_internalformats = sizeof(valid_gl_internalformats) / sizeof(valid_gl_internalformats[0]); |
| |
| /** An array of texture targets that is used by a number of TextureViewUtilities methods. */ |
| static glw::GLenum valid_texture_targets[] = { GL_TEXTURE_1D, |
| GL_TEXTURE_1D_ARRAY, |
| GL_TEXTURE_2D, |
| GL_TEXTURE_2D_ARRAY, |
| GL_TEXTURE_2D_MULTISAMPLE, |
| GL_TEXTURE_2D_MULTISAMPLE_ARRAY, |
| GL_TEXTURE_3D, |
| GL_TEXTURE_BUFFER, |
| GL_TEXTURE_CUBE_MAP, |
| GL_TEXTURE_CUBE_MAP_ARRAY, |
| GL_TEXTURE_RECTANGLE }; |
| const unsigned int n_valid_texture_targets = sizeof(valid_texture_targets) / sizeof(valid_texture_targets[0]); |
| |
| /** Retrieves amount of components defined by user-specified internalformat. |
| * |
| * This function throws TestError exception if @param internalformat is not recognized. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested value. |
| **/ |
| unsigned int TextureViewUtilities::getAmountOfComponentsForInternalformat(const glw::GLenum internalformat) |
| { |
| unsigned int result = 0; |
| |
| switch (internalformat) |
| { |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_RGB10_A2: |
| case GL_RGB10_A2UI: |
| case GL_RGB5_A1: |
| case GL_RGBA16F: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA16: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA32F: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| case GL_RGBA4: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_SRGB8_ALPHA8: |
| { |
| result = 4; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| case GL_R11F_G11F_B10F: |
| case GL_RGB16_SNORM: |
| case GL_RGB16F: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB16: |
| case GL_RGB32F: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| case GL_RGB565: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB9_E5: |
| case GL_SRGB8: |
| { |
| result = 3; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG16_SNORM: |
| case GL_RG32F: |
| case GL_RG32I: |
| case GL_RG32UI: |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| case GL_RG8I: |
| case GL_RG8UI: |
| { |
| result = 2; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH32F_STENCIL8: /* only one piece of information can be retrieved at a time */ |
| case GL_DEPTH24_STENCIL8: /* only one piece of information can be retrieved at a time */ |
| case GL_R16: |
| case GL_R16_SNORM: |
| case GL_R16F: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32F: |
| case GL_R32I: |
| case GL_R32UI: |
| case GL_R8_SNORM: |
| case GL_R8: |
| case GL_R8I: |
| case GL_R8UI: |
| { |
| result = 1; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (interalformat) */ |
| |
| return result; |
| } |
| |
| /** Retrieves block size used by user-specified compressed internalformat. |
| * |
| * Throws TestError exception if @param internalformat is not recognized. |
| * |
| * @param internalformat Compressed internalformat to use for the query. |
| * |
| * @return Requested information (in bytes). |
| **/ |
| unsigned int TextureViewUtilities::getBlockSizeForCompressedInternalformat(const glw::GLenum internalformat) |
| { |
| unsigned int result = 0; |
| |
| switch (internalformat) |
| { |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| { |
| result = 8; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| { |
| result = 16; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (internalformat) */ |
| |
| return result; |
| } |
| |
| /** Retrieves amount of bits used for R/G/B/A components by user-specified |
| * *non-compressed* internalformat. |
| * |
| * Throws TestError exception if @param internalformat is not recognized. |
| * |
| * @param internalformat Internalformat to use for the query. Must not describe |
| * compressed internalformat. |
| * @param out_rgba_size Must be spacious enough to hold 4 ints. Deref will be |
| * used to store requested information for R/G/B/A channels. |
| * Must not be NULL. |
| **/ |
| void TextureViewUtilities::getComponentSizeForInternalformat(const glw::GLenum internalformat, |
| unsigned int* out_rgba_size) |
| { |
| /* Note: Compressed textures are not supported by this function */ |
| |
| /* Reset all the values before we continue. */ |
| memset(out_rgba_size, 0, 4 /* rgba */ * sizeof(unsigned int)); |
| |
| /* Depending on the user-specified internalformat, update relevant arguments */ |
| switch (internalformat) |
| { |
| case GL_RGBA32F: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| { |
| out_rgba_size[0] = 32; |
| out_rgba_size[1] = 32; |
| out_rgba_size[2] = 32; |
| out_rgba_size[3] = 32; |
| |
| break; |
| } |
| |
| case GL_RGBA16F: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA16: |
| case GL_RGBA16_SNORM: |
| { |
| out_rgba_size[0] = 16; |
| out_rgba_size[1] = 16; |
| out_rgba_size[2] = 16; |
| out_rgba_size[3] = 16; |
| |
| break; |
| } |
| |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_SRGB8_ALPHA8: |
| { |
| out_rgba_size[0] = 8; |
| out_rgba_size[1] = 8; |
| out_rgba_size[2] = 8; |
| out_rgba_size[3] = 8; |
| |
| break; |
| } |
| |
| case GL_RGB10_A2: |
| case GL_RGB10_A2UI: |
| { |
| out_rgba_size[0] = 10; |
| out_rgba_size[1] = 10; |
| out_rgba_size[2] = 10; |
| out_rgba_size[3] = 2; |
| |
| break; |
| } |
| |
| case GL_RGB5_A1: |
| { |
| out_rgba_size[0] = 5; |
| out_rgba_size[1] = 5; |
| out_rgba_size[2] = 5; |
| out_rgba_size[3] = 1; |
| |
| break; |
| } |
| |
| case GL_RGBA4: |
| { |
| out_rgba_size[0] = 4; |
| out_rgba_size[1] = 4; |
| out_rgba_size[2] = 4; |
| out_rgba_size[3] = 4; |
| |
| break; |
| } |
| |
| case GL_RGB9_E5: |
| { |
| out_rgba_size[0] = 9; |
| out_rgba_size[1] = 9; |
| out_rgba_size[2] = 9; |
| out_rgba_size[3] = 5; |
| |
| break; |
| } |
| |
| case GL_R11F_G11F_B10F: |
| { |
| out_rgba_size[0] = 11; |
| out_rgba_size[1] = 11; |
| out_rgba_size[2] = 10; |
| |
| break; |
| } |
| |
| case GL_RGB565: |
| { |
| out_rgba_size[0] = 5; |
| out_rgba_size[1] = 6; |
| out_rgba_size[2] = 5; |
| |
| break; |
| } |
| |
| case GL_RGB32F: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| { |
| out_rgba_size[0] = 32; |
| out_rgba_size[1] = 32; |
| out_rgba_size[2] = 32; |
| |
| break; |
| } |
| |
| case GL_RGB16_SNORM: |
| case GL_RGB16F: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB16: |
| { |
| out_rgba_size[0] = 16; |
| out_rgba_size[1] = 16; |
| out_rgba_size[2] = 16; |
| |
| break; |
| } |
| |
| case GL_RGB8_SNORM: |
| case GL_RGB8: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_SRGB8: |
| { |
| out_rgba_size[0] = 8; |
| out_rgba_size[1] = 8; |
| out_rgba_size[2] = 8; |
| |
| break; |
| } |
| |
| case GL_RG32F: |
| case GL_RG32I: |
| case GL_RG32UI: |
| { |
| out_rgba_size[0] = 32; |
| out_rgba_size[1] = 32; |
| |
| break; |
| } |
| |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG16_SNORM: |
| { |
| out_rgba_size[0] = 16; |
| out_rgba_size[1] = 16; |
| |
| break; |
| } |
| |
| case GL_RG8: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG8_SNORM: |
| { |
| out_rgba_size[0] = 8; |
| out_rgba_size[1] = 8; |
| |
| break; |
| } |
| |
| case GL_R32F: |
| case GL_R32I: |
| case GL_R32UI: |
| { |
| out_rgba_size[0] = 32; |
| |
| break; |
| } |
| |
| case GL_R16F: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R16: |
| case GL_R16_SNORM: |
| case GL_DEPTH_COMPONENT16: |
| { |
| out_rgba_size[0] = 16; |
| |
| break; |
| } |
| |
| case GL_R8: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R8_SNORM: |
| { |
| out_rgba_size[0] = 8; |
| |
| break; |
| } |
| |
| case GL_DEPTH_COMPONENT24: |
| { |
| out_rgba_size[0] = 24; |
| |
| break; |
| } |
| |
| case GL_DEPTH32F_STENCIL8: |
| { |
| out_rgba_size[0] = 32; |
| out_rgba_size[1] = 8; |
| |
| break; |
| } |
| |
| case GL_DEPTH24_STENCIL8: |
| { |
| out_rgba_size[0] = 24; |
| out_rgba_size[1] = 8; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (interalformat) */ |
| } |
| |
| /** Tells how many bits per components should be used to define input data with |
| * user-specified type. |
| * |
| * Throws TestError exception if @param type is not recognized. |
| * |
| * @param type Type to use for the query. |
| * @param out_rgba_size Deref will be used to store requested information. Must |
| * not be NULL. Must be capacious enough to hold 4 ints. |
| * |
| **/ |
| void TextureViewUtilities::getComponentSizeForType(const glw::GLenum type, unsigned int* out_rgba_size) |
| { |
| memset(out_rgba_size, 0, sizeof(unsigned int) * 4 /* rgba */); |
| |
| switch (type) |
| { |
| case GL_BYTE: |
| case GL_UNSIGNED_BYTE: |
| { |
| out_rgba_size[0] = 8; |
| out_rgba_size[1] = 8; |
| out_rgba_size[2] = 8; |
| out_rgba_size[3] = 8; |
| |
| break; |
| } |
| |
| case GL_FLOAT: |
| case GL_UNSIGNED_INT: |
| case GL_INT: |
| { |
| out_rgba_size[0] = 32; |
| out_rgba_size[1] = 32; |
| out_rgba_size[2] = 32; |
| out_rgba_size[3] = 32; |
| |
| break; |
| } |
| |
| case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: |
| { |
| out_rgba_size[0] = 8; |
| out_rgba_size[1] = 24; |
| out_rgba_size[2] = 32; |
| out_rgba_size[3] = 0; |
| |
| break; |
| } |
| |
| case GL_HALF_FLOAT: |
| case GL_UNSIGNED_SHORT: |
| case GL_SHORT: |
| { |
| out_rgba_size[0] = 16; |
| out_rgba_size[1] = 16; |
| out_rgba_size[2] = 16; |
| out_rgba_size[3] = 16; |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_10_10_10_2: |
| { |
| out_rgba_size[0] = 10; |
| out_rgba_size[1] = 10; |
| out_rgba_size[2] = 10; |
| out_rgba_size[3] = 2; |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_10F_11F_11F_REV: |
| { |
| out_rgba_size[0] = 11; |
| out_rgba_size[1] = 11; |
| out_rgba_size[2] = 10; |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_24_8: |
| { |
| out_rgba_size[0] = 24; |
| out_rgba_size[1] = 8; |
| out_rgba_size[2] = 0; |
| out_rgba_size[3] = 0; |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| { |
| out_rgba_size[0] = 10; |
| out_rgba_size[1] = 10; |
| out_rgba_size[2] = 10; |
| out_rgba_size[3] = 2; |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_5_9_9_9_REV: |
| { |
| out_rgba_size[0] = 9; |
| out_rgba_size[1] = 9; |
| out_rgba_size[2] = 9; |
| out_rgba_size[3] = 5; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized type"); |
| } |
| } /* switch (type) */ |
| } |
| |
| /** Returns strings naming GL error codes. |
| * |
| * @param error_code GL error code. |
| * |
| * @return Requested strings or "[?]" if @param error_code was not |
| * recognized. |
| **/ |
| const char* TextureViewUtilities::getErrorCodeString(const glw::GLint error_code) |
| { |
| switch (error_code) |
| { |
| case GL_INVALID_ENUM: |
| return "GL_INVALID_ENUM"; |
| case GL_INVALID_FRAMEBUFFER_OPERATION: |
| return "GL_INVALID_FRAMEBUFFER_OPERATION"; |
| case GL_INVALID_OPERATION: |
| return "GL_INVALID_OPERATION"; |
| case GL_INVALID_VALUE: |
| return "GL_INVALID_VALUE"; |
| case GL_NO_ERROR: |
| return "GL_NO_ERROR"; |
| case GL_OUT_OF_MEMORY: |
| return "GL_OUT_OF_MEMORY"; |
| case GL_STACK_OVERFLOW: |
| return "GL_STACK_OVERFLOW"; |
| case GL_STACK_UNDERFLOW: |
| return "GL_STACK_UNDERFLOW"; |
| default: |
| return "[?]"; |
| } |
| } |
| |
| /** Tells what the format of user-specified internalformat is (eg. whether it's a FP, |
| * unorm, snorm, etc.). Note: this is NOT the GL-speak format. |
| * |
| * Supports both compressed and non-compressed internalformats. |
| * Throws TestError exception if @param internalformat is not recognized. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested information. |
| * |
| **/ |
| _format TextureViewUtilities::getFormatOfInternalformat(const glw::GLenum internalformat) |
| { |
| _format result = FORMAT_UNDEFINED; |
| |
| switch (internalformat) |
| { |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_RGBA16: |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| case GL_RGB16: |
| case GL_RGB5_A1: |
| case GL_RGB565: |
| case GL_RGB8: |
| case GL_RG16: |
| case GL_RG8: |
| case GL_R16: |
| case GL_R8: |
| case GL_SRGB8: |
| case GL_SRGB8_ALPHA8: |
| { |
| result = FORMAT_UNORM; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA8_SNORM: |
| case GL_RGB16_SNORM: |
| case GL_RGB8_SNORM: |
| case GL_RG16_SNORM: |
| case GL_RG8_SNORM: |
| case GL_R16_SNORM: |
| case GL_R8_SNORM: |
| { |
| result = FORMAT_SNORM; |
| |
| break; |
| } |
| |
| case GL_RGB10_A2UI: |
| case GL_RGBA16UI: |
| case GL_RGBA32UI: |
| case GL_RGBA8UI: |
| case GL_RGB16UI: |
| case GL_RGB32UI: |
| case GL_RGB8UI: |
| case GL_RG16UI: |
| case GL_RG32UI: |
| case GL_RG8UI: |
| case GL_R16UI: |
| case GL_R32UI: |
| case GL_R8UI: |
| { |
| result = FORMAT_UNSIGNED_INTEGER; |
| |
| break; |
| } |
| |
| case GL_RGB9_E5: |
| { |
| result = FORMAT_RGBE; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT32F: |
| case GL_R11F_G11F_B10F: |
| case GL_RGBA16F: |
| case GL_RGBA32F: |
| case GL_RGB16F: |
| case GL_RGB32F: |
| case GL_RG16F: |
| case GL_RG32F: |
| case GL_R16F: |
| case GL_R32F: |
| { |
| result = FORMAT_FLOAT; |
| |
| break; |
| } |
| |
| case GL_RGBA16I: |
| case GL_RGBA32I: |
| case GL_RGBA8I: |
| case GL_RGB16I: |
| case GL_RGB32I: |
| case GL_RGB8I: |
| case GL_RG16I: |
| case GL_RG32I: |
| case GL_RG8I: |
| case GL_R16I: |
| case GL_R32I: |
| case GL_R8I: |
| { |
| result = FORMAT_SIGNED_INTEGER; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (interalformat) */ |
| |
| return result; |
| } |
| |
| /** Returns GL format that is compatible with user-specified internalformat. |
| * |
| * Throws TestError exception if @param internalformat is not recognized. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested information. |
| **/ |
| glw::GLenum TextureViewUtilities::getGLFormatOfInternalformat(const glw::GLenum internalformat) |
| { |
| glw::GLenum result = FORMAT_UNDEFINED; |
| |
| switch (internalformat) |
| { |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| { |
| result = GL_COMPRESSED_RGBA; |
| |
| break; |
| } |
| |
| case GL_RGB10_A2: |
| case GL_RGB5_A1: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA32F: |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_SRGB8_ALPHA8: |
| { |
| result = GL_RGBA; |
| |
| break; |
| } |
| |
| case GL_RGB10_A2UI: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| { |
| result = GL_RGBA_INTEGER; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RGB8_ETC2: |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| case GL_COMPRESSED_SRGB8_ETC2: |
| { |
| result = GL_COMPRESSED_RGB; |
| |
| break; |
| } |
| |
| case GL_R11F_G11F_B10F: |
| case GL_RGB16: |
| case GL_RGB16_SNORM: |
| case GL_RGB16F: |
| case GL_RGB32F: |
| case GL_RGB565: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_RGB9_E5: |
| case GL_SRGB8: |
| { |
| result = GL_RGB; |
| |
| break; |
| } |
| |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| { |
| result = GL_RGB_INTEGER; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_RG11_EAC: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| case GL_COMPRESSED_SIGNED_RG11_EAC: |
| { |
| result = GL_COMPRESSED_RG; |
| |
| break; |
| } |
| |
| case GL_RG16: |
| case GL_RG16_SNORM: |
| case GL_RG16F: |
| case GL_RG32F: |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| { |
| result = GL_RG; |
| |
| break; |
| } |
| |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG32I: |
| case GL_RG32UI: |
| case GL_RG8I: |
| case GL_RG8UI: |
| { |
| result = GL_RG_INTEGER; |
| |
| break; |
| } |
| |
| case GL_COMPRESSED_R11_EAC: |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_R11_EAC: |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| { |
| result = GL_COMPRESSED_RED; |
| |
| break; |
| } |
| |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16_SNORM: |
| case GL_R32F: |
| case GL_R8: |
| case GL_R8_SNORM: |
| { |
| result = GL_RED; |
| |
| break; |
| } |
| |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32I: |
| case GL_R32UI: |
| case GL_R8I: |
| case GL_R8UI: |
| { |
| result = GL_RED_INTEGER; |
| |
| break; |
| } |
| |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT32F: |
| { |
| result = GL_DEPTH_COMPONENT; |
| |
| break; |
| } |
| |
| case GL_DEPTH24_STENCIL8: |
| case GL_DEPTH32F_STENCIL8: |
| { |
| result = GL_DEPTH_STENCIL; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (internalformat) */ |
| |
| return result; |
| } |
| |
| /** Returns a string that corresponds to a GLSL type that can act as input to user-specified |
| * sampler type, and which can hold user-specified amount of components. |
| * |
| * Throws TestError exception if either of the arguments was found invalid. |
| * |
| * @param sampler_type Type of the sampler to use for the query. |
| * @param n_components Amount of components to use for the query. |
| * |
| * @return Requested string. |
| **/ |
| const char* TextureViewUtilities::getGLSLDataTypeForSamplerType(const _sampler_type sampler_type, |
| const unsigned int n_components) |
| { |
| const char* result = ""; |
| |
| switch (sampler_type) |
| { |
| case SAMPLER_TYPE_FLOAT: |
| { |
| switch (n_components) |
| { |
| case 1: |
| result = "float"; |
| break; |
| case 2: |
| result = "vec2"; |
| break; |
| case 3: |
| result = "vec3"; |
| break; |
| case 4: |
| result = "vec4"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unsupported number of components"); |
| } |
| } /* switch (n_components) */ |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_SIGNED_INTEGER: |
| { |
| switch (n_components) |
| { |
| case 1: |
| result = "int"; |
| break; |
| case 2: |
| result = "ivec2"; |
| break; |
| case 3: |
| result = "ivec3"; |
| break; |
| case 4: |
| result = "ivec4"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unsupported number of components"); |
| } |
| } /* switch (n_components) */ |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_UNSIGNED_INTEGER: |
| { |
| switch (n_components) |
| { |
| case 1: |
| result = "uint"; |
| break; |
| case 2: |
| result = "uvec2"; |
| break; |
| case 3: |
| result = "uvec3"; |
| break; |
| case 4: |
| result = "uvec4"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unsupported number of components"); |
| } |
| } /* switch (n_components) */ |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized sampler type"); |
| } |
| } /* switch (sampler_type) */ |
| |
| return result; |
| } |
| |
| /** Retrieves a string defining a sampler type in GLSL which corresponds to user-specified internal |
| * sampler type. |
| * |
| * Throws TestError exception if @param sampler_type was not recognized. |
| * |
| * @param sampler_type Internal sampler type to use for the query. |
| * |
| * @return Requested string. |
| **/ |
| const char* TextureViewUtilities::getGLSLTypeForSamplerType(const _sampler_type sampler_type) |
| { |
| const char* result = ""; |
| |
| switch (sampler_type) |
| { |
| case SAMPLER_TYPE_FLOAT: |
| result = "sampler2D"; |
| break; |
| case SAMPLER_TYPE_SIGNED_INTEGER: |
| result = "isampler2D"; |
| break; |
| case SAMPLER_TYPE_UNSIGNED_INTEGER: |
| result = "usampler2D"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized sampler type"); |
| } |
| } /* switch (sampler_type) */ |
| |
| return result; |
| } |
| |
| /** Returns a vector of texture+view internalformat combinations that are known to be incompatible. |
| * |
| * @return Requested information. |
| **/ |
| TextureViewUtilities::_incompatible_internalformat_pairs TextureViewUtilities:: |
| getIllegalTextureAndViewInternalformatCombinations() |
| { |
| TextureViewUtilities::_incompatible_internalformat_pairs result; |
| |
| /* Iterate in two loops over the set of supported internalformats */ |
| for (int n_texture_internalformat = 0; |
| n_texture_internalformat < |
| (n_internalformat_view_compatibility_array_entries / 2); /* the array stores two values per entry */ |
| ++n_texture_internalformat) |
| { |
| glw::GLenum src_internalformat = internalformat_view_compatibility_array[(n_texture_internalformat * 2) + 0]; |
| _view_class src_view_class = |
| (_view_class)internalformat_view_compatibility_array[(n_texture_internalformat * 2) + 1]; |
| |
| for (int n_view_internalformat = n_texture_internalformat + 1; |
| n_view_internalformat < (n_internalformat_view_compatibility_array_entries >> 1); ++n_view_internalformat) |
| { |
| glw::GLenum view_internalformat = internalformat_view_compatibility_array[(n_view_internalformat * 2) + 0]; |
| _view_class view_view_class = |
| (_view_class)internalformat_view_compatibility_array[(n_view_internalformat * 2) + 1]; |
| |
| if (src_view_class != view_view_class) |
| { |
| result.push_back(_internalformat_pair(src_internalformat, view_internalformat)); |
| } |
| } /* for (all internalformats we can use for the texture view) */ |
| } /* for (all internalformats we can use for the parent texture) */ |
| |
| return result; |
| } |
| |
| /** Returns a vector of texture+view target texture combinations that are known to be incompatible. |
| * |
| * @return Requested information. |
| **/ |
| TextureViewUtilities::_incompatible_texture_target_pairs TextureViewUtilities:: |
| getIllegalTextureAndViewTargetCombinations() |
| { |
| _incompatible_texture_target_pairs result; |
| |
| /* Iterate through all combinations of texture targets and store those that are |
| * reported as invalid |
| */ |
| for (unsigned int n_parent_texture_target = 0; n_parent_texture_target < n_valid_texture_targets; |
| ++n_parent_texture_target) |
| { |
| glw::GLenum parent_texture_target = valid_texture_targets[n_parent_texture_target]; |
| |
| for (unsigned int n_view_texture_target = 0; n_view_texture_target < n_valid_texture_targets; |
| ++n_view_texture_target) |
| { |
| glw::GLenum view_texture_target = valid_texture_targets[n_view_texture_target]; |
| |
| if (!isLegalTextureTargetForTextureView(parent_texture_target, view_texture_target)) |
| { |
| result.push_back(_internalformat_pair(parent_texture_target, view_texture_target)); |
| } |
| } /* for (all texture targets considered for views) */ |
| } /* for (all texture targets considered for parent texture) */ |
| |
| return result; |
| } |
| |
| /** Returns internalformats associated with user-specified view class. |
| * |
| * @param view_class View class to use for the query. |
| * |
| * @return Requested information. |
| **/ |
| TextureViewUtilities::_internalformats TextureViewUtilities::getInternalformatsFromViewClass(_view_class view_class) |
| { |
| _internalformats result; |
| |
| /* Iterate over the data array and push those internalformats that match the requested view class */ |
| const unsigned int n_array_elements = n_internalformat_view_compatibility_array_entries; |
| |
| for (unsigned int n_array_pair = 0; n_array_pair < (n_array_elements >> 1); ++n_array_pair) |
| { |
| const glw::GLenum internalformat = internalformat_view_compatibility_array[n_array_pair * 2 + 0]; |
| const _view_class current_view_class = |
| (_view_class)internalformat_view_compatibility_array[n_array_pair * 2 + 1]; |
| |
| if (current_view_class == view_class) |
| { |
| result.push_back(internalformat); |
| } |
| } /* for (all pairs in the data array) */ |
| |
| return result; |
| } |
| |
| /** Returns a string defining user-specified internalformat. |
| * |
| * Throws a TestError exception if @param internalformat was not recognized. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested string. |
| **/ |
| const char* TextureViewUtilities::getInternalformatString(const glw::GLenum internalformat) |
| { |
| const char* result = "[?]"; |
| |
| switch (internalformat) |
| { |
| case GL_RGBA32F: |
| result = "GL_RGBA32F"; |
| break; |
| case GL_RGBA32I: |
| result = "GL_RGBA32I"; |
| break; |
| case GL_RGBA32UI: |
| result = "GL_RGBA32UI"; |
| break; |
| case GL_RGBA16: |
| result = "GL_RGBA16"; |
| break; |
| case GL_RGBA16F: |
| result = "GL_RGBA16F"; |
| break; |
| case GL_RGBA16I: |
| result = "GL_RGBA16I"; |
| break; |
| case GL_RGBA16UI: |
| result = "GL_RGBA16UI"; |
| break; |
| case GL_RGBA8: |
| result = "GL_RGBA8"; |
| break; |
| case GL_RGBA8I: |
| result = "GL_RGBA8I"; |
| break; |
| case GL_RGBA8UI: |
| result = "GL_RGBA8UI"; |
| break; |
| case GL_SRGB8_ALPHA8: |
| result = "GL_SRGB8_ALPHA8"; |
| break; |
| case GL_RGB10_A2: |
| result = "GL_RGB10_A2"; |
| break; |
| case GL_RGB10_A2UI: |
| result = "GL_RGB10_A2UI"; |
| break; |
| case GL_RGB5_A1: |
| result = "GL_RGB5_A1"; |
| break; |
| case GL_RGBA4: |
| result = "GL_RGBA4"; |
| break; |
| case GL_R11F_G11F_B10F: |
| result = "GL_R11F_G11F_B10F"; |
| break; |
| case GL_RGB565: |
| result = "GL_RGB565"; |
| break; |
| case GL_RG32F: |
| result = "GL_RG32F"; |
| break; |
| case GL_RG32I: |
| result = "GL_RG32I"; |
| break; |
| case GL_RG32UI: |
| result = "GL_RG32UI"; |
| break; |
| case GL_RG16: |
| result = "GL_RG16"; |
| break; |
| case GL_RG16F: |
| result = "GL_RG16F"; |
| break; |
| case GL_RG16I: |
| result = "GL_RG16I"; |
| break; |
| case GL_RG16UI: |
| result = "GL_RG16UI"; |
| break; |
| case GL_RG8: |
| result = "GL_RG8"; |
| break; |
| case GL_RG8I: |
| result = "GL_RG8I"; |
| break; |
| case GL_RG8UI: |
| result = "GL_RG8UI"; |
| break; |
| case GL_R32F: |
| result = "GL_R32F"; |
| break; |
| case GL_R32I: |
| result = "GL_R32I"; |
| break; |
| case GL_R32UI: |
| result = "GL_R32UI"; |
| break; |
| case GL_R16F: |
| result = "GL_R16F"; |
| break; |
| case GL_R16I: |
| result = "GL_R16I"; |
| break; |
| case GL_R16UI: |
| result = "GL_R16UI"; |
| break; |
| case GL_R16: |
| result = "GL_R16"; |
| break; |
| case GL_R8: |
| result = "GL_R8"; |
| break; |
| case GL_R8I: |
| result = "GL_R8I"; |
| break; |
| case GL_R8UI: |
| result = "GL_R8UI"; |
| break; |
| case GL_RGBA16_SNORM: |
| result = "GL_RGBA16_SNORM"; |
| break; |
| case GL_RGBA8_SNORM: |
| result = "GL_RGBA8_SNORM"; |
| break; |
| case GL_RGB32F: |
| result = "GL_RGB32F"; |
| break; |
| case GL_RGB32I: |
| result = "GL_RGB32I"; |
| break; |
| case GL_RGB32UI: |
| result = "GL_RGB32UI"; |
| break; |
| case GL_RGB16_SNORM: |
| result = "GL_RGB16_SNORM"; |
| break; |
| case GL_RGB16F: |
| result = "GL_RGB16F"; |
| break; |
| case GL_RGB16I: |
| result = "GL_RGB16I"; |
| break; |
| case GL_RGB16UI: |
| result = "GL_RGB16UI"; |
| break; |
| case GL_RGB16: |
| result = "GL_RGB16"; |
| break; |
| case GL_RGB8_SNORM: |
| result = "GL_RGB8_SNORM"; |
| break; |
| case GL_RGB8: |
| result = "GL_RGB8"; |
| break; |
| case GL_RGB8I: |
| result = "GL_RGB8I"; |
| break; |
| case GL_RGB8UI: |
| result = "GL_RGB8UI"; |
| break; |
| case GL_SRGB8: |
| result = "GL_SRGB8"; |
| break; |
| case GL_RGB9_E5: |
| result = "GL_RGB9_E5"; |
| break; |
| case GL_RG16_SNORM: |
| result = "GL_RG16_SNORM"; |
| break; |
| case GL_RG8_SNORM: |
| result = "GL_RG8_SNORM"; |
| break; |
| case GL_R16_SNORM: |
| result = "GL_R16_SNORM"; |
| break; |
| case GL_R8_SNORM: |
| result = "GL_R8_SNORM"; |
| break; |
| case GL_DEPTH_COMPONENT32F: |
| result = "GL_DEPTH_COMPONENT32F"; |
| break; |
| case GL_DEPTH_COMPONENT24: |
| result = "GL_DEPTH_COMPONENT24"; |
| break; |
| case GL_DEPTH_COMPONENT16: |
| result = "GL_DEPTH_COMPONENT16"; |
| break; |
| case GL_DEPTH32F_STENCIL8: |
| result = "GL_DEPTH32F_STENCIL8"; |
| break; |
| case GL_DEPTH24_STENCIL8: |
| result = "GL_DEPTH24_STENCIL8"; |
| break; |
| case GL_COMPRESSED_RED_RGTC1: |
| result = "GL_COMPRESSED_RED_RGTC1"; |
| break; |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| result = "GL_COMPRESSED_SIGNED_RED_RGTC1"; |
| break; |
| case GL_COMPRESSED_RG_RGTC2: |
| result = "GL_COMPRESSED_RG_RGTC2"; |
| break; |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| result = "GL_COMPRESSED_SIGNED_RG_RGTC2"; |
| break; |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| result = "GL_COMPRESSED_RGBA_BPTC_UNORM"; |
| break; |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| result = "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM"; |
| break; |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| result = "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT"; |
| break; |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| result = "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT"; |
| break; |
| case GL_COMPRESSED_RGB8_ETC2: |
| result = "GL_COMPRESSED_RGB8_ETC2"; |
| break; |
| case GL_COMPRESSED_SRGB8_ETC2: |
| result = "GL_COMPRESSED_SRGB8_ETC2"; |
| break; |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| result = "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"; |
| break; |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| result = "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"; |
| break; |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: |
| result = "GL_COMPRESSED_RGBA8_ETC2_EAC"; |
| break; |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: |
| result = "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"; |
| break; |
| case GL_COMPRESSED_R11_EAC: |
| result = "GL_COMPRESSED_R11_EAC"; |
| break; |
| case GL_COMPRESSED_SIGNED_R11_EAC: |
| result = "GL_COMPRESSED_SIGNED_R11_EAC"; |
| break; |
| case GL_COMPRESSED_RG11_EAC: |
| result = "GL_COMPRESSED_RG11_EAC"; |
| break; |
| case GL_COMPRESSED_SIGNED_RG11_EAC: |
| result = "GL_COMPRESSED_SIGNED_RG11_EAC"; |
| break; |
| |
| default: |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| |
| return result; |
| } |
| |
| /** Returns all texture+view internalformat pairs that are valid in light of GL_ARB_texture_view specification. |
| * |
| * @return As described. |
| **/ |
| TextureViewUtilities::_compatible_internalformat_pairs TextureViewUtilities:: |
| getLegalTextureAndViewInternalformatCombinations() |
| { |
| _compatible_internalformat_pairs result; |
| |
| /* Iterate over all view classes */ |
| for (int current_view_class_it = static_cast<int>(VIEW_CLASS_FIRST); |
| current_view_class_it != static_cast<int>(VIEW_CLASS_COUNT); current_view_class_it++) |
| { |
| _view_class current_view_class = static_cast<_view_class>(current_view_class_it); |
| _internalformats view_class_internalformats = getInternalformatsFromViewClass(current_view_class); |
| |
| /* Store all combinations in the result vector */ |
| for (_internalformats_const_iterator left_iterator = view_class_internalformats.begin(); |
| left_iterator != view_class_internalformats.end(); left_iterator++) |
| { |
| for (_internalformats_const_iterator right_iterator = view_class_internalformats.begin(); |
| right_iterator != view_class_internalformats.end(); ++right_iterator) |
| { |
| result.push_back(_internalformat_pair(*left_iterator, *right_iterator)); |
| } /* for (all internalformats to be used as right-side values) */ |
| } /* for (all internalformats to be used as left-side values) */ |
| } /* for (all view classes) */ |
| |
| return result; |
| } |
| |
| /** Returns all valid texture+view texture targets pairs. |
| * |
| * @return As per description. |
| **/ |
| TextureViewUtilities::_compatible_texture_target_pairs TextureViewUtilities::getLegalTextureAndViewTargetCombinations() |
| { |
| _compatible_texture_target_pairs result; |
| |
| /* Iterate over all texture targets valid for a glTextureView() call. Consider each one of them as |
| * original texture target. |
| */ |
| for (unsigned int n_original_texture_target = 0; n_original_texture_target < n_valid_texture_targets; |
| ++n_original_texture_target) |
| { |
| const glw::GLenum original_texture_target = valid_texture_targets[n_original_texture_target]; |
| |
| /* Iterate again, but this time consider each texture target as a valid new target */ |
| for (unsigned int n_compatible_texture_target = 0; n_compatible_texture_target < n_valid_texture_targets; |
| ++n_compatible_texture_target) |
| { |
| const glw::GLenum view_texture_target = valid_texture_targets[n_compatible_texture_target]; |
| |
| if (TextureViewUtilities::isLegalTextureTargetForTextureView(original_texture_target, view_texture_target)) |
| { |
| result.push_back(_texture_target_pair(original_texture_target, view_texture_target)); |
| } |
| } /* for (all texture targets that are potentially compatible) */ |
| } /* for (all original texture targets) */ |
| |
| return result; |
| } |
| |
| /** Returns major & minor version for user-specified CTS rendering context type. |
| * |
| * @param context_type CTS rendering context type. |
| * @param out_major_version Deref will be used to store major version. Must not be NULL. |
| * @param out_minor_version Deref will be used to store minor version. Must not be NULL. |
| * |
| **/ |
| void TextureViewUtilities::getMajorMinorVersionFromContextVersion(const glu::ContextType& context_type, |
| glw::GLint* out_major_version, |
| glw::GLint* out_minor_version) |
| { |
| if (context_type.getAPI() == glu::ApiType::core(4, 0)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 0; |
| } |
| else if (context_type.getAPI() == glu::ApiType::core(4, 1)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 1; |
| } |
| else if (context_type.getAPI() == glu::ApiType::core(4, 2)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 2; |
| } |
| else if (context_type.getAPI() == glu::ApiType::core(4, 3)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 3; |
| } |
| else if (context_type.getAPI() == glu::ApiType::core(4, 4)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 4; |
| } |
| else if (context_type.getAPI() == glu::ApiType::core(4, 5)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 5; |
| } |
| else if (context_type.getAPI() == glu::ApiType::core(4, 6)) |
| { |
| *out_major_version = 4; |
| *out_minor_version = 6; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized rendering context version"); |
| } |
| } |
| |
| /** Tells which sampler can be used to sample a texture defined with user-specified |
| * internalformat. |
| * |
| * Supports both compressed and non-compressed internalformats. |
| * Throws TestError exception if @param internalformat was not recognized. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested information. |
| **/ |
| _sampler_type TextureViewUtilities::getSamplerTypeForInternalformat(const glw::GLenum internalformat) |
| { |
| _sampler_type result = SAMPLER_TYPE_UNDEFINED; |
| |
| /* Compressed internalformats not supported at the moment */ |
| |
| switch (internalformat) |
| { |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT32F: |
| case GL_RGBA16: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA16F: |
| case GL_RGBA32F: |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_RGB10_A2: |
| case GL_RGB16: |
| case GL_RGB16_SNORM: |
| case GL_RGB16F: |
| case GL_RGB32F: |
| case GL_RGB5_A1: |
| case GL_RGB565: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_RGB9_E5: |
| case GL_RG16: |
| case GL_RG16_SNORM: |
| case GL_RG16F: |
| case GL_RG32F: |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| case GL_R11F_G11F_B10F: |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16_SNORM: |
| case GL_R32F: |
| case GL_R8: |
| case GL_R8_SNORM: |
| case GL_SRGB8_ALPHA8: |
| case GL_SRGB8: |
| { |
| result = SAMPLER_TYPE_FLOAT; |
| |
| break; |
| } |
| |
| case GL_RGB10_A2UI: |
| case GL_RGBA32UI: |
| case GL_RGBA16UI: |
| case GL_RGBA8UI: |
| case GL_RGB16UI: |
| case GL_RGB32UI: |
| case GL_RGB8UI: |
| case GL_RG16UI: |
| case GL_RG32UI: |
| case GL_RG8UI: |
| case GL_R16UI: |
| case GL_R32UI: |
| case GL_R8UI: |
| { |
| result = SAMPLER_TYPE_UNSIGNED_INTEGER; |
| |
| break; |
| } |
| |
| case GL_RGBA16I: |
| case GL_RGBA32I: |
| case GL_RGBA8I: |
| case GL_RGB16I: |
| case GL_RGB32I: |
| case GL_RGB8I: |
| case GL_RG16I: |
| case GL_RG32I: |
| case GL_RG8I: |
| case GL_R16I: |
| case GL_R32I: |
| case GL_R8I: |
| { |
| result = SAMPLER_TYPE_SIGNED_INTEGER; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (interalformat) */ |
| |
| return result; |
| } |
| |
| /** Tells how many bytes are required to define a texture mip-map using |
| * user-specified internalformat and type, assuming user-defined mip-map |
| * resolution. Compressed internalformats are NOT supported. |
| * |
| * Throws TestError exception if @param internalformat or @param type are |
| * found invalid. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * @param type Type to use for the query. |
| * @param width Mip-map width to use for the query. |
| * @param height Mip-map height to use for the query. |
| * |
| * @return Requested information. |
| **/ |
| unsigned int TextureViewUtilities::getTextureDataSize(const glw::GLenum internalformat, const glw::GLenum type, |
| const unsigned int width, const unsigned int height) |
| { |
| unsigned int internalformat_rgba_size[4] = { 0 }; |
| unsigned int type_rgba_size[4] = { 0 }; |
| unsigned int texel_size = 0; |
| |
| TextureViewUtilities::getComponentSizeForInternalformat(internalformat, internalformat_rgba_size); |
| TextureViewUtilities::getComponentSizeForType(type, type_rgba_size); |
| |
| if (internalformat_rgba_size[0] == 0) |
| { |
| type_rgba_size[0] = 0; |
| } |
| |
| if (internalformat_rgba_size[1] == 0) |
| { |
| type_rgba_size[1] = 0; |
| } |
| |
| if (internalformat_rgba_size[2] == 0) |
| { |
| type_rgba_size[2] = 0; |
| } |
| |
| if (internalformat_rgba_size[3] == 0) |
| { |
| type_rgba_size[3] = 0; |
| } |
| |
| texel_size = type_rgba_size[0] + type_rgba_size[1] + type_rgba_size[2] + type_rgba_size[3]; |
| |
| /* Current implementation assumes we do not need to use bit resolution when |
| * preparing texel data. Make extra sure we're not wrong. */ |
| DE_ASSERT((texel_size % 8) == 0); |
| |
| texel_size /= 8; /* bits per byte */ |
| |
| return texel_size * width * height; |
| } |
| |
| /** Returns a string corresponding to a GL enum describing a texture target. |
| * |
| * @return As per description or "[?]" if the enum was not recognized. |
| **/ |
| const char* TextureViewUtilities::getTextureTargetString(const glw::GLenum texture_target) |
| { |
| const char* result = "[?]"; |
| |
| switch (texture_target) |
| { |
| case GL_TEXTURE_1D: |
| result = "GL_TEXTURE_1D"; |
| break; |
| case GL_TEXTURE_1D_ARRAY: |
| result = "GL_TEXTURE_1D_ARRAY"; |
| break; |
| case GL_TEXTURE_2D: |
| result = "GL_TEXTURE_2D"; |
| break; |
| case GL_TEXTURE_2D_ARRAY: |
| result = "GL_TEXTURE_2D_ARRAY"; |
| break; |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| result = "GL_TEXTURE_2D_MULTISAMPLE"; |
| break; |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| result = "GL_TEXTURE_2D_MULTISAMPLE_ARRAY"; |
| break; |
| case GL_TEXTURE_3D: |
| result = "GL_TEXTURE_3D"; |
| break; |
| case GL_TEXTURE_BUFFER: |
| result = "GL_TEXTURE_BUFFER"; |
| break; |
| case GL_TEXTURE_CUBE_MAP: |
| result = "GL_TEXTURE_CUBE_MAP"; |
| break; |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| result = "GL_TEXTURE_CUBE_MAP_ARRAY"; |
| break; |
| case GL_TEXTURE_RECTANGLE: |
| result = "GL_TEXTURE_RECTANGLE"; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Returns GL type that can be used to define a texture mip-map defined |
| * with an internalformat of @param internalformat. |
| * |
| * Throws TestError exception if @param internalformat was found to be invalid. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested information. |
| **/ |
| glw::GLenum TextureViewUtilities::getTypeCompatibleWithInternalformat(const glw::GLenum internalformat) |
| { |
| glw::GLenum result = GL_NONE; |
| |
| /* Compressed internalformats not supported at the moment */ |
| |
| switch (internalformat) |
| { |
| case GL_RGBA8_SNORM: |
| case GL_RGB8_SNORM: |
| case GL_RG8_SNORM: |
| case GL_R8_SNORM: |
| case GL_RGBA8I: |
| case GL_RGB8I: |
| case GL_RG8I: |
| case GL_R8I: |
| { |
| result = GL_BYTE; |
| |
| break; |
| } |
| |
| case GL_DEPTH24_STENCIL8: |
| { |
| result = GL_UNSIGNED_INT_24_8; |
| |
| break; |
| } |
| |
| case GL_DEPTH32F_STENCIL8: |
| { |
| result = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; |
| |
| break; |
| } |
| |
| case GL_RGBA16F: |
| case GL_RGB16F: |
| case GL_RG16F: |
| case GL_R16F: |
| { |
| result = GL_HALF_FLOAT; |
| |
| break; |
| } |
| |
| case GL_DEPTH_COMPONENT32F: |
| case GL_RGBA32F: |
| case GL_RGB32F: |
| case GL_RG32F: |
| case GL_R11F_G11F_B10F: |
| case GL_R32F: |
| { |
| result = GL_FLOAT; |
| |
| break; |
| } |
| |
| case GL_RGBA16_SNORM: |
| case GL_RGB16_SNORM: |
| case GL_RG16_SNORM: |
| case GL_R16_SNORM: |
| { |
| result = GL_SHORT; |
| |
| break; |
| } |
| |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| case GL_RGB5_A1: |
| case GL_RGB565: |
| case GL_RGB8: |
| case GL_RGB9_E5: |
| case GL_RG8: |
| case GL_R8: |
| case GL_SRGB8_ALPHA8: |
| case GL_SRGB8: |
| case GL_RGBA8UI: |
| case GL_RGB8UI: |
| case GL_RG8UI: |
| case GL_R8UI: |
| { |
| result = GL_UNSIGNED_BYTE; |
| |
| break; |
| } |
| |
| case GL_R16I: |
| case GL_RGBA16I: |
| case GL_RGB16I: |
| case GL_RG16I: |
| { |
| result = GL_SHORT; |
| |
| break; |
| } |
| |
| case GL_DEPTH_COMPONENT16: |
| case GL_RGBA16: |
| case GL_RGB16: |
| case GL_RG16: |
| case GL_R16: |
| case GL_RGBA16UI: |
| case GL_RGB16UI: |
| case GL_RG16UI: |
| case GL_R16UI: |
| { |
| result = GL_UNSIGNED_SHORT; |
| |
| break; |
| } |
| |
| case GL_RGBA32I: |
| case GL_RGB32I: |
| case GL_RG32I: |
| case GL_R32I: |
| { |
| result = GL_INT; |
| |
| break; |
| } |
| |
| case GL_DEPTH_COMPONENT24: |
| case GL_RGBA32UI: |
| case GL_RGB32UI: |
| case GL_RG32UI: |
| case GL_R32UI: |
| { |
| result = GL_UNSIGNED_INT; |
| |
| break; |
| } |
| |
| case GL_RGB10_A2UI: |
| { |
| result = GL_UNSIGNED_INT_2_10_10_10_REV; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| } /* switch (interalformat) */ |
| |
| return result; |
| } |
| |
| /** Tells what view class is the user-specified internalformat associated with. |
| * |
| * Implements Table 8.21 from OpenGL Specification 4.3 |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return Requested information or VIEW_CLASS_UNDEFINED if @param internalformat |
| * has not been recognized. |
| **/ |
| _view_class TextureViewUtilities::getViewClassForInternalformat(const glw::GLenum internalformat) |
| { |
| _view_class result = VIEW_CLASS_UNDEFINED; |
| |
| /* Note that n_internalformat_view_compatibility_array_entries needs to be divided by 2 |
| * because the value refers to a total number of entries in the array, not to the number |
| * of pairs that can be read. |
| */ |
| for (int n_entry = 0; n_entry < (n_internalformat_view_compatibility_array_entries >> 1); n_entry++) |
| { |
| glw::GLenum array_internalformat = internalformat_view_compatibility_array[(n_entry * 2) + 0]; |
| _view_class view_class = (_view_class)internalformat_view_compatibility_array[(n_entry * 2) + 1]; |
| |
| if (array_internalformat == internalformat) |
| { |
| result = view_class; |
| |
| break; |
| } |
| } /* for (all pairs in data array) */ |
| |
| return result; |
| } |
| |
| /** Initializes texture storage for either an immutable or mutable texture object, |
| * depending on configuration of the test run the storage is to be initialized for. |
| * |
| * @param gl GL entry-points to use for storage initialization. |
| * @param init_mutable_to true if a mutable texture storage should be initialized, |
| * false to initialize immutable texture storage. |
| * @param texture_target Texture target to be used. |
| * @param texture_depth Depth to be used for texture storage. Only used |
| * for texture targets that use the depth information. |
| * @param texture_height Height to be used for texture storage. Only used |
| * for texture targets that use the height information. |
| * @param texture_width Width to be used for texture storage. |
| * @param texture_internalformat Internalformat to be used for texture storage. |
| * @param texture_format Format to be used for texture storage. |
| * @param texture_type Type to be used for texture storage. |
| * @param n_levels_needed Amount of mip-map levels that should be used for texture storage. |
| * Only used for texture targets that support mip-maps. |
| * @param n_cubemaps_needed Amount of cube-maps to be used for initialization of cube map |
| * array texture storage. Only used if @param texture_internalformat |
| * is set to GL_TEXTURE_CUBE_MAP_ARRAY. |
| * @param bo_id ID of a buffer object to be used for initialization of |
| * buffer texture storage. Only used if @param texture_internalformat |
| * is set to GL_TEXTURE_BUFFEER. |
| * |
| **/ |
| void TextureViewUtilities::initTextureStorage(const glw::Functions& gl, bool init_mutable_to, |
| glw::GLenum texture_target, glw::GLint texture_depth, |
| glw::GLint texture_height, glw::GLint texture_width, |
| glw::GLenum texture_internalformat, glw::GLenum texture_format, |
| glw::GLenum texture_type, unsigned int n_levels_needed, |
| unsigned int n_cubemaps_needed, glw::GLint bo_id) |
| { |
| const glw::GLenum cubemap_texture_targets[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; |
| const unsigned int n_cubemap_texture_targets = sizeof(cubemap_texture_targets) / sizeof(cubemap_texture_targets[0]); |
| |
| /* If we're going to be initializing a multisample texture object, |
| * determine how many samples can be used for GL_RGBA8 internalformat, |
| * given texture target that is of our interest */ |
| glw::GLint gl_max_color_texture_samples_value = 0; |
| |
| gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &gl_max_color_texture_samples_value); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_COLOR_TEXTURE_SAMPLES"); |
| |
| if (texture_target == GL_TEXTURE_BUFFER) |
| { |
| gl.texBuffer(GL_TEXTURE_BUFFER, texture_internalformat, bo_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexBuffer() call failed for GL_TEXTURE_BUFFER target"); |
| } |
| else if (init_mutable_to) |
| { |
| for (unsigned int n_level = 0; n_level < n_levels_needed; ++n_level) |
| { |
| /* If level != 0 and we're trying to initialize a texture target which |
| * only accepts a single level, leave now |
| */ |
| if (n_level != 0 && |
| (texture_target == GL_TEXTURE_RECTANGLE || texture_target == GL_TEXTURE_2D_MULTISAMPLE || |
| texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || texture_target == GL_TEXTURE_BUFFER)) |
| { |
| break; |
| } |
| |
| /* Initialize mutable texture storage */ |
| switch (texture_target) |
| { |
| case GL_TEXTURE_1D: |
| { |
| gl.texImage1D(texture_target, n_level, texture_internalformat, texture_width >> n_level, 0, /* border */ |
| texture_format, texture_type, DE_NULL); /* pixels */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage1D() call failed for GL_TEXTURE_1D texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_1D_ARRAY: |
| case GL_TEXTURE_2D: |
| case GL_TEXTURE_RECTANGLE: |
| { |
| gl.texImage2D(texture_target, n_level, texture_internalformat, texture_width >> n_level, |
| texture_height >> n_level, 0, /* border */ |
| texture_format, texture_type, DE_NULL); /* pixels */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| (texture_target == GL_TEXTURE_1D_ARRAY) ? |
| "glTexImage2D() call failed for GL_TEXTURE_1D_ARRAY texture target" : |
| (texture_target == GL_TEXTURE_2D) ? |
| "glTexImage2D() call failed for GL_TEXTURE_2D texture target" : |
| "glTexImage2D() call failed for GL_TEXTURE_RECTANGLE texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_ARRAY: |
| case GL_TEXTURE_3D: |
| { |
| gl.texImage3D(texture_target, n_level, texture_internalformat, texture_width >> n_level, |
| texture_height >> n_level, texture_depth >> n_level, 0, /* border */ |
| texture_format, texture_type, DE_NULL); /* pixels */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| (texture_target == GL_TEXTURE_2D_ARRAY) ? |
| "glTexImage3D() call failed for GL_TEXTURE_2D_ARRAY texture target" : |
| "glTexImage3D() call failed for GL_TEXTURE_3D texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| gl.texImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, gl_max_color_texture_samples_value, |
| texture_internalformat, texture_width >> n_level, texture_height >> n_level, |
| GL_TRUE); /* fixedsamplelocations */ |
| |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glTexImage2DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| gl.texImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, gl_max_color_texture_samples_value, |
| texture_internalformat, texture_width >> n_level, texture_height >> n_level, |
| texture_depth >> n_level, GL_TRUE); /* fixedsamplelocations */ |
| |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glTexImage3DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE_ARRAY texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP: |
| { |
| for (unsigned int n_cubemap_texture_target = 0; n_cubemap_texture_target < n_cubemap_texture_targets; |
| ++n_cubemap_texture_target) |
| { |
| glw::GLenum cubemap_texture_target = cubemap_texture_targets[n_cubemap_texture_target]; |
| |
| gl.texImage2D(cubemap_texture_target, n_level, texture_internalformat, texture_width >> n_level, |
| texture_height >> n_level, 0, /* border */ |
| texture_format, texture_type, DE_NULL); /* pixels */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| "glTexImage2D() call failed for one of the cube-map texture targets"); |
| } /* for (all cube-map texture targets) */ |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| gl.texImage3D(texture_target, n_level, texture_internalformat, texture_width >> n_level, |
| texture_height >> n_level, 6 /* layer-faces */ * n_cubemaps_needed, 0, /* border */ |
| texture_format, texture_type, DE_NULL); /* pixels */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| "glTexImage3D() call failed for GL_TEXTURE_CUBE_MAP_ARRAY texture target"); |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture target"); |
| } |
| } /* switch (texture_target) */ |
| } /* for (all levels) */ |
| } /* if (texture_type == TEST_TEXTURE_TYPE_MUTABLE_TEXTURE_OBJECT) */ |
| else |
| { |
| /* Initialize immutable texture storage */ |
| switch (texture_target) |
| { |
| case GL_TEXTURE_1D: |
| { |
| gl.texStorage1D(texture_target, n_levels_needed, texture_internalformat, texture_width); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage1D() call failed for GL_TEXTURE_1D texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_1D_ARRAY: |
| case GL_TEXTURE_2D: |
| case GL_TEXTURE_CUBE_MAP: |
| case GL_TEXTURE_RECTANGLE: |
| { |
| const unsigned n_levels = (texture_target == GL_TEXTURE_RECTANGLE) ? 1 : n_levels_needed; |
| |
| gl.texStorage2D(texture_target, n_levels, texture_internalformat, texture_width, texture_height); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| (texture_target == GL_TEXTURE_1D_ARRAY) ? |
| "glTexStorage2D() call failed for GL_TEXTURE_1D_ARRAY texture target" : |
| (texture_target == GL_TEXTURE_2D) ? |
| "glTexStorage2D() call failed for GL_TEXTURE_2D texture target" : |
| (texture_target == GL_TEXTURE_CUBE_MAP) ? |
| "glTexStorage2D() call failed for GL_TEXTURE_CUBE_MAP texture target" : |
| "glTexStorage2D() call failed for GL_TEXTURE_RECTANGLE texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_ARRAY: |
| case GL_TEXTURE_3D: |
| { |
| gl.texStorage3D(texture_target, n_levels_needed, texture_internalformat, texture_width, texture_height, |
| texture_depth); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| (texture_target == GL_TEXTURE_2D_ARRAY) ? |
| "glTexStorage3D() call failed for GL_TEXTURE_2D_ARRAY texture target" : |
| "glTexStorage3D() call failed for GL_TEXTURE_3D texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, gl_max_color_texture_samples_value, |
| texture_internalformat, texture_width, texture_height, |
| GL_TRUE); /* fixedsamplelocations */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| "glTexStorage2DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, gl_max_color_texture_samples_value, |
| texture_internalformat, texture_width, texture_height, texture_depth, |
| GL_TRUE); /* fixedsamplelocations */ |
| |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glTexStorage3DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE_ARRAY texture target"); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| const unsigned int actual_texture_depth = 6 /* layer-faces */ * n_cubemaps_needed; |
| |
| gl.texStorage3D(texture_target, n_levels_needed, texture_internalformat, texture_width, texture_height, |
| actual_texture_depth); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| "glTexStorage3D() call failed for GL_TEXTURE_CUBE_MAP_ARRAY texture target"); |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture target"); |
| } |
| } /* switch (texture_target) */ |
| } |
| } |
| |
| /** Tells whether a parent texture object, storage of which uses @param original_internalformat |
| * internalformat, can be used to generate a texture view using @param view_internalformat |
| * internalformat. |
| * |
| * @param original_internalformat Internalformat used for parent texture object storage. |
| * @param view_internalformat Internalformat to be used for view texture object storage. |
| * |
| * @return true if the internalformats are compatible, false otherwise. |
| **/ |
| bool TextureViewUtilities::isInternalformatCompatibleForTextureView(glw::GLenum original_internalformat, |
| glw::GLenum view_internalformat) |
| { |
| const _view_class original_internalformat_view_class = getViewClassForInternalformat(original_internalformat); |
| const _view_class view_internalformat_view_class = getViewClassForInternalformat(view_internalformat); |
| |
| return (original_internalformat_view_class == view_internalformat_view_class); |
| } |
| |
| /** Tells whether user-specified internalformat is compressed. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return true if @param internalformat is a known compressed internalformat, |
| * false otherwise. |
| **/ |
| bool TextureViewUtilities::isInternalformatCompressed(const glw::GLenum internalformat) |
| { |
| bool result = false; |
| |
| switch (internalformat) |
| { |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| case GL_COMPRESSED_RGB8_ETC2: |
| case GL_COMPRESSED_SRGB8_ETC2: |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: |
| case GL_COMPRESSED_R11_EAC: |
| case GL_COMPRESSED_SIGNED_R11_EAC: |
| case GL_COMPRESSED_RG11_EAC: |
| case GL_COMPRESSED_SIGNED_RG11_EAC: |
| { |
| result = true; |
| |
| break; |
| } |
| } /* switch (internalformat) */ |
| |
| return result; |
| } |
| |
| /** Tells whether user-specified internalformat operates in sRGB color space. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * |
| * @return true if @param internalformat is a known sRGB internalformat, |
| * false otherwise. |
| **/ |
| bool TextureViewUtilities::isInternalformatSRGB(const glw::GLenum internalformat) |
| { |
| return (internalformat == GL_SRGB8 || internalformat == GL_SRGB8_ALPHA8 || |
| internalformat == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM); |
| } |
| |
| /** Tells whether user-specified internalformat is supported by OpenGL of a given version. |
| * |
| * @param internalformat Internalformat to use for the query. |
| * @param major_version Major version of the rendering context. |
| * @param minor_version Minor version of the rendering context. |
| * |
| * @return true if the internalformat is supported, false otherwise. |
| **/ |
| bool TextureViewUtilities::isInternalformatSupported(glw::GLenum internalformat, const glw::GLint major_version, |
| const glw::GLint minor_version) |
| { |
| (void)major_version; |
| /* NOTE: This function, as it stands right now, does not consider OpenGL contexts |
| * lesser than 4. |
| **/ |
| glw::GLint minimum_minor_version = 0; |
| |
| DE_ASSERT(major_version >= 4); |
| |
| switch (internalformat) |
| { |
| /* >= OpenGL 4.0 */ |
| case GL_RGBA32F: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA8: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_SRGB8_ALPHA8: |
| case GL_RGB10_A2: |
| case GL_RGB10_A2UI: |
| case GL_RGB5_A1: |
| case GL_RGBA4: |
| case GL_R11F_G11F_B10F: |
| case GL_RG32F: |
| case GL_RG32I: |
| case GL_RG32UI: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG8: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_R32F: |
| case GL_R32I: |
| case GL_R32UI: |
| case GL_R16F: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R16: |
| case GL_R8: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA8_SNORM: |
| case GL_RGB32F: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| case GL_RGB16_SNORM: |
| case GL_RGB16F: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB16: |
| case GL_RGB8_SNORM: |
| case GL_RGB8: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_SRGB8: |
| case GL_RGB9_E5: |
| case GL_RG16_SNORM: |
| case GL_RG8_SNORM: |
| case GL_R16_SNORM: |
| case GL_R8_SNORM: |
| case GL_DEPTH_COMPONENT32F: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH32F_STENCIL8: |
| case GL_DEPTH24_STENCIL8: |
| case GL_COMPRESSED_RED_RGTC1: |
| case GL_COMPRESSED_SIGNED_RED_RGTC1: |
| case GL_COMPRESSED_RG_RGTC2: |
| case GL_COMPRESSED_SIGNED_RG_RGTC2: |
| { |
| /* Already covered by default value of minimum_minor_version */ |
| |
| break; |
| } |
| |
| /* >= OpenGL 4.2 */ |
| case GL_RGB565: |
| case GL_COMPRESSED_RGBA_BPTC_UNORM: |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: |
| { |
| minimum_minor_version = 2; |
| |
| break; |
| } |
| |
| /* >= OpenGL 4.3 */ |
| case GL_COMPRESSED_RGB8_ETC2: |
| case GL_COMPRESSED_SRGB8_ETC2: |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: |
| case GL_COMPRESSED_R11_EAC: |
| case GL_COMPRESSED_SIGNED_R11_EAC: |
| case GL_COMPRESSED_RG11_EAC: |
| case GL_COMPRESSED_SIGNED_RG11_EAC: |
| { |
| minimum_minor_version = 3; |
| |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized internalformat"); |
| } |
| |
| return (minor_version >= minimum_minor_version); |
| } |
| |
| /** Tells whether a parent texture object using @param original_texture_target texture target |
| * can be used to generate a texture view of @param view_texture_target texture target. |
| * |
| * @param original_texture_target Texture target used by parent texture; |
| * @param view_texture_target Texture target to be used for view texture; |
| * |
| * @return true if the texture targets are compatible, false otherwise. |
| **/ |
| bool TextureViewUtilities::isLegalTextureTargetForTextureView(glw::GLenum original_texture_target, |
| glw::GLenum view_texture_target) |
| { |
| bool result = false; |
| |
| switch (original_texture_target) |
| { |
| case GL_TEXTURE_1D: |
| { |
| result = (view_texture_target == GL_TEXTURE_1D || view_texture_target == GL_TEXTURE_1D_ARRAY); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D: |
| { |
| result = (view_texture_target == GL_TEXTURE_2D || view_texture_target == GL_TEXTURE_2D_ARRAY); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_3D: |
| { |
| result = (view_texture_target == GL_TEXTURE_3D); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP: |
| { |
| result = (view_texture_target == GL_TEXTURE_CUBE_MAP || view_texture_target == GL_TEXTURE_2D || |
| view_texture_target == GL_TEXTURE_2D_ARRAY || view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_RECTANGLE: |
| { |
| result = (view_texture_target == GL_TEXTURE_RECTANGLE); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_BUFFER: |
| { |
| /* No targets supported */ |
| |
| break; |
| } |
| |
| case GL_TEXTURE_1D_ARRAY: |
| { |
| result = (view_texture_target == GL_TEXTURE_1D_ARRAY || view_texture_target == GL_TEXTURE_1D); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_ARRAY: |
| { |
| result = (view_texture_target == GL_TEXTURE_2D_ARRAY || view_texture_target == GL_TEXTURE_2D || |
| view_texture_target == GL_TEXTURE_CUBE_MAP || view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| result = (view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY || view_texture_target == GL_TEXTURE_2D_ARRAY || |
| view_texture_target == GL_TEXTURE_2D || view_texture_target == GL_TEXTURE_CUBE_MAP); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| result = (view_texture_target == GL_TEXTURE_2D_MULTISAMPLE || |
| view_texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| result = (view_texture_target == GL_TEXTURE_2D_MULTISAMPLE || |
| view_texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); |
| |
| break; |
| } |
| } /* switch (original_texture_target) */ |
| |
| return result; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| **/ |
| TextureViewTestGetTexParameter::TextureViewTestGetTexParameter(deqp::Context& context) |
| : TestCase(context, "gettexparameter", "Verifies glGetTexParameterfv() and glGetTexParameteriv() " |
| "work as specified") |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** De-initializes all GL objects created for the test. */ |
| void TextureViewTestGetTexParameter::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Deinitialize all test runs */ |
| for (_test_runs_iterator it = m_test_runs.begin(); it != m_test_runs.end(); ++it) |
| { |
| _test_run& test_run = *it; |
| |
| if (test_run.parent_texture_object_id != 0) |
| { |
| gl.deleteTextures(1, &test_run.parent_texture_object_id); |
| |
| test_run.parent_texture_object_id = 0; |
| } |
| |
| if (test_run.texture_view_object_created_from_immutable_to_id != 0) |
| { |
| gl.deleteTextures(1, &test_run.texture_view_object_created_from_immutable_to_id); |
| |
| test_run.texture_view_object_created_from_immutable_to_id = 0; |
| } |
| |
| if (test_run.texture_view_object_created_from_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &test_run.texture_view_object_created_from_view_to_id); |
| |
| test_run.texture_view_object_created_from_view_to_id = 0; |
| } |
| } |
| m_test_runs.clear(); |
| } |
| |
| /** Initializes test run descriptors used by the test. This also includes |
| * all GL objects used by all the iterations. |
| **/ |
| void TextureViewTestGetTexParameter::initTestRuns() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const int n_cubemaps_needed = 4; /* only used for GL_TEXTURE_CUBE_MAP_ARRAY */ |
| const int texture_depth = 16; |
| const int texture_height = 32; |
| const int texture_width = 64; |
| |
| const glw::GLenum texture_targets[] = { |
| GL_TEXTURE_1D, GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D, |
| GL_TEXTURE_2D_ARRAY, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, |
| GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_ARRAY, |
| GL_TEXTURE_RECTANGLE |
| }; |
| const _test_texture_type texture_types[] = { TEST_TEXTURE_TYPE_NO_STORAGE_ALLOCATED, |
| TEST_TEXTURE_TYPE_IMMUTABLE_TEXTURE_OBJECT, |
| TEST_TEXTURE_TYPE_MUTABLE_TEXTURE_OBJECT, |
| TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_IMMUTABLE_TEXTURE_OBJECT, |
| TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_TEXTURE_VIEW }; |
| const unsigned int n_texture_targets = sizeof(texture_targets) / sizeof(texture_targets[0]); |
| const unsigned int n_texture_types = sizeof(texture_types) / sizeof(texture_types[0]); |
| |
| /* Iterate through all texture types supported by the test */ |
| for (unsigned int n_texture_type = 0; n_texture_type < n_texture_types; ++n_texture_type) |
| { |
| const _test_texture_type texture_type = texture_types[n_texture_type]; |
| |
| /* Iterate through all texture targets supported by the test */ |
| for (unsigned int n_texture_target = 0; n_texture_target < n_texture_targets; ++n_texture_target) |
| { |
| _test_run new_test_run; |
| const glw::GLenum texture_target = texture_targets[n_texture_target]; |
| |
| /* Texture buffers are neither immutable nor mutable. In order to avoid testing |
| * them in both cases, let's assume they are immutable objects */ |
| if (texture_target == GL_TEXTURE_BUFFER && texture_type == TEST_TEXTURE_TYPE_MUTABLE_TEXTURE_OBJECT) |
| { |
| continue; |
| } |
| |
| /* Set up test run properties. Since we're only testing a single |
| * configuration, we can set these to predefined values.. |
| */ |
| const int n_levels_needed = 6; |
| glw::GLint n_min_layer = 1; |
| glw::GLint n_num_layers = 2; |
| glw::GLint n_min_level = 2; |
| glw::GLint n_num_levels = 3; |
| int parent_texture_depth = texture_depth; |
| int parent_texture_height = texture_height; |
| int parent_texture_width = texture_width; |
| |
| new_test_run.texture_target = texture_target; |
| new_test_run.texture_type = texture_type; |
| |
| /* Take note of target-specific restrictions */ |
| if (texture_target == GL_TEXTURE_CUBE_MAP || texture_target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| n_num_layers = 6 /* layer-faces */ * 2; /* as per spec */ |
| |
| /* Make sure that cube face width matches its height */ |
| parent_texture_height = 64; |
| parent_texture_width = 64; |
| |
| /* Also change the depth so that there's at least a few layers |
| * we can use in the test for GL_TEXTURE_CUBE_MAP_ARRAY case |
| */ |
| parent_texture_depth = 64; |
| } |
| |
| if (texture_target == GL_TEXTURE_CUBE_MAP) |
| { |
| /* Texture views created from a cube map texture should always |
| * use a minimum layer of zero |
| */ |
| n_min_layer = 0; |
| n_num_layers = 6; |
| } |
| |
| if (texture_target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| /* Slightly modify the values we'll use for <minlayer> |
| * and <numlayers> arguments passed to glTextureView() calls |
| * so that we can test the "view from view from texture" case |
| */ |
| n_min_layer = 0; |
| } |
| |
| if (texture_target == GL_TEXTURE_1D || texture_target == GL_TEXTURE_2D || |
| texture_target == GL_TEXTURE_2D_MULTISAMPLE || texture_target == GL_TEXTURE_3D || |
| texture_target == GL_TEXTURE_RECTANGLE) |
| { |
| /* All these texture targets are single-layer only. glTextureView() |
| * also requires <numlayers> argument to be set to 1 for them, so |
| * take this into account. |
| **/ |
| n_min_layer = 0; |
| n_num_layers = 1; |
| } |
| |
| if (texture_target == GL_TEXTURE_2D_MULTISAMPLE || texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || |
| texture_target == GL_TEXTURE_RECTANGLE) |
| { |
| /* All these texture targets do not support mip-maps */ |
| n_min_level = 0; |
| } |
| |
| /* Initialize parent texture object */ |
| gl.genTextures(1, &new_test_run.parent_texture_object_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed"); |
| |
| gl.bindTexture(texture_target, new_test_run.parent_texture_object_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| if (texture_type != TEST_TEXTURE_TYPE_NO_STORAGE_ALLOCATED) |
| { |
| TextureViewUtilities::initTextureStorage(gl, (texture_type == TEST_TEXTURE_TYPE_MUTABLE_TEXTURE_OBJECT), |
| texture_target, parent_texture_depth, parent_texture_height, |
| parent_texture_width, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, |
| n_levels_needed, n_cubemaps_needed, 0); /* bo_id */ |
| } |
| |
| /* Update expected view-specific property values to include interactions |
| * with immutable textures. */ |
| if (texture_type == TEST_TEXTURE_TYPE_IMMUTABLE_TEXTURE_OBJECT || |
| texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_IMMUTABLE_TEXTURE_OBJECT || |
| texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_TEXTURE_VIEW) |
| { |
| /* Set expected GL_TEXTURE_IMMUTABLE_LEVELS property value to the number |
| * of levels we'll be using for the immutable texture storage. For selected |
| * texture targets that do no take <levels> argument, we'll change this |
| * value on a case-by-case basis. |
| */ |
| new_test_run.expected_n_immutable_levels = n_levels_needed; |
| |
| /* Set expected GL_TEXTURE_VIEW_NUM_LAYERS property value to 1, as per GL spec. |
| * This value will be modified for selected texture targets */ |
| new_test_run.expected_n_num_layers = 1; |
| |
| /* Configured expected GL_TEXTURE_VIEW_NUM_LEVELS value as per GL spec */ |
| new_test_run.expected_n_num_levels = n_levels_needed; |
| |
| /* Initialize immutable texture storage */ |
| switch (texture_target) |
| { |
| case GL_TEXTURE_1D_ARRAY: |
| { |
| /* Update expected GL_TEXTURE_VIEW_NUM_LAYERS property value as per GL specification */ |
| new_test_run.expected_n_num_layers = texture_height; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP: |
| { |
| /* Update expected GL_TEXTURE_VIEW_NUM_LAYERS property value as per GL specification */ |
| new_test_run.expected_n_num_layers = 6; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_RECTANGLE: |
| { |
| new_test_run.expected_n_immutable_levels = 1; |
| new_test_run.expected_n_num_levels = 1; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_ARRAY: |
| { |
| /* Update expected GL_TEXTURE_VIEW_NUM_LAYERS property value as per GL specification */ |
| new_test_run.expected_n_num_layers = texture_depth; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| /* 2D multisample texture are not mip-mapped, so update |
| * expected GL_TEXTURE_IMMUTABLE_LEVELS and GL_TEXTURE_VIEW_NUM_LEVELS |
| * value accordingly */ |
| new_test_run.expected_n_immutable_levels = 1; |
| new_test_run.expected_n_num_levels = 1; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| /* 2D multisample array textures are not mip-mapped, so update |
| * expected GL_TEXTURE_IMMUTABLE_LEVELS and GL_TEXTURE_VIEW_NUM_LEVELS |
| * values accordingly */ |
| new_test_run.expected_n_immutable_levels = 1; |
| new_test_run.expected_n_num_levels = 1; |
| |
| /* Update expected GL_TEXTURE_VIEW_NUM_LAYERS property value as per GL specification */ |
| new_test_run.expected_n_num_layers = texture_depth; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| const unsigned int actual_texture_depth = 6 /* layer-faces */ * n_cubemaps_needed; |
| |
| /* Update expected GL_TEXTURE_VIEW_NUM_LAYERS property value as per GL specification */ |
| new_test_run.expected_n_num_layers = actual_texture_depth; |
| |
| break; |
| } |
| } /* switch (texture_target) */ |
| } |
| |
| /* Initialize the view(s) */ |
| if (texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_IMMUTABLE_TEXTURE_OBJECT || |
| texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_TEXTURE_VIEW) |
| { |
| const unsigned int n_iterations = |
| (texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_TEXTURE_VIEW) ? 2 : 1; |
| |
| for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration) |
| { |
| glw::GLuint* parent_id_ptr = (n_iteration == 0) ? |
| &new_test_run.parent_texture_object_id : |
| &new_test_run.texture_view_object_created_from_immutable_to_id; |
| glw::GLuint* view_id_ptr = (n_iteration == 0) ? |
| &new_test_run.texture_view_object_created_from_immutable_to_id : |
| &new_test_run.texture_view_object_created_from_view_to_id; |
| |
| gl.genTextures(1, view_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed"); |
| |
| gl.textureView(*view_id_ptr, new_test_run.texture_target, *parent_id_ptr, |
| GL_RGBA8, /* use the parent texture object's internalformat */ |
| n_min_level, n_num_levels, n_min_layer, n_num_layers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed"); |
| |
| /* Query parent object's properties */ |
| glw::GLint parent_min_level = -1; |
| glw::GLint parent_min_layer = -1; |
| glw::GLint parent_num_layers = -1; |
| glw::GLint parent_num_levels = -1; |
| glw::GLint parent_n_immutable_levels = -1; |
| |
| gl.bindTexture(texture_target, *parent_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.getTexParameteriv(texture_target, GL_TEXTURE_IMMUTABLE_LEVELS, &parent_n_immutable_levels); |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glGetTexParameteriv() failed for GL_TEXTURE_IMMUTABLE_LEVELS pname queried for parent object"); |
| |
| gl.getTexParameteriv(texture_target, GL_TEXTURE_VIEW_MIN_LAYER, &parent_min_layer); |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_MIN_LAYER pname queried for parent object"); |
| |
| gl.getTexParameteriv(texture_target, GL_TEXTURE_VIEW_MIN_LEVEL, &parent_min_level); |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_MIN_LEVEL pname queried for parent object"); |
| |
| gl.getTexParameteriv(texture_target, GL_TEXTURE_VIEW_NUM_LAYERS, &parent_num_layers); |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_NUM_LAYERS pname queried for parent object"); |
| |
| gl.getTexParameteriv(texture_target, GL_TEXTURE_VIEW_NUM_LEVELS, &parent_num_levels); |
| GLU_EXPECT_NO_ERROR( |
| gl.getError(), |
| "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_NUM_LEVELS pname queried for parent object"); |
| |
| /* Update test run-specific expected values as per GL_ARB_texture_view extension specification */ |
| /* |
| * - TEXTURE_IMMUTABLE_LEVELS is set to the value of TEXTURE_IMMUTABLE_LEVELS |
| * from the original texture. |
| */ |
| new_test_run.expected_n_immutable_levels = parent_n_immutable_levels; |
| |
| /* |
| * - TEXTURE_VIEW_MIN_LEVEL is set to <minlevel> plus the value of |
| * TEXTURE_VIEW_MIN_LEVEL from the original texture. |
| */ |
| new_test_run.expected_n_min_level = n_min_level + parent_min_level; |
| |
| /* |
| * - TEXTURE_VIEW_MIN_LAYER is set to <minlayer> plus the value of |
| * TEXTURE_VIEW_MIN_LAYER from the original texture. |
| */ |
| new_test_run.expected_n_min_layer = n_min_layer + parent_min_layer; |
| |
| /* |
| * - TEXTURE_VIEW_NUM_LAYERS is set to the lesser of <numlayers> and the |
| * value of TEXTURE_VIEW_NUM_LAYERS from the original texture minus |
| * <minlayer>. |
| * |
| */ |
| if ((parent_num_layers - n_min_layer) < n_num_layers) |
| { |
| new_test_run.expected_n_num_layers = parent_num_layers - n_min_layer; |
| } |
| else |
| { |
| new_test_run.expected_n_num_layers = n_num_layers; |
| } |
| |
| /* |
| * - TEXTURE_VIEW_NUM_LEVELS is set to the lesser of <numlevels> and the |
| * value of TEXTURE_VIEW_NUM_LEVELS from the original texture minus |
| * <minlevels>. |
| * |
| */ |
| if ((parent_num_levels - n_min_level) < n_num_levels) |
| { |
| new_test_run.expected_n_num_levels = parent_num_levels - n_min_level; |
| } |
| else |
| { |
| new_test_run.expected_n_num_levels = n_num_levels; |
| } |
| } /* for (all iterations) */ |
| } /* if (texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_IMMUTABLE_TEXTURE_OBJECT || |
| texture_type == TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_TEXTURE_VIEW) */ |
| |
| /* Store the descriptor */ |
| m_test_runs.push_back(new_test_run); |
| } /* for (all texture targets) */ |
| } /* for (all texture types) */ |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestGetTexParameter::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Make sure GL_ARB_texture_view is reported as supported before carrying on |
| * with actual execution */ |
| const std::vector<std::string>& extensions = m_context.getContextInfo().getExtensions(); |
| |
| if (std::find(extensions.begin(), extensions.end(), "GL_ARB_texture_view") == extensions.end()) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported"); |
| } |
| |
| /* Initialize all objects necessary to execute the test */ |
| initTestRuns(); |
| |
| /* Iterate through all test runs and issue the queries */ |
| for (_test_runs_const_iterator test_run_iterator = m_test_runs.begin(); test_run_iterator != m_test_runs.end(); |
| test_run_iterator++) |
| { |
| glw::GLfloat query_texture_immutable_levels_value_float = -1.0f; |
| glw::GLint query_texture_immutable_levels_value_int = -1; |
| glw::GLfloat query_texture_view_min_layer_value_float = -1.0f; |
| glw::GLint query_texture_view_min_layer_value_int = -1; |
| glw::GLfloat query_texture_view_min_level_value_float = -1.0f; |
| glw::GLint query_texture_view_min_level_value_int = -1; |
| glw::GLfloat query_texture_view_num_layers_value_float = -1.0f; |
| glw::GLint query_texture_view_num_layers_value_int = -1; |
| glw::GLfloat query_texture_view_num_levels_value_float = -1.0f; |
| glw::GLint query_texture_view_num_levels_value_int = -1; |
| const _test_run& test_run = *test_run_iterator; |
| glw::GLint texture_object_id = 0; |
| |
| switch (test_run.texture_type) |
| { |
| case TEST_TEXTURE_TYPE_IMMUTABLE_TEXTURE_OBJECT: |
| texture_object_id = test_run.parent_texture_object_id; |
| break; |
| case TEST_TEXTURE_TYPE_MUTABLE_TEXTURE_OBJECT: |
| texture_object_id = test_run.parent_texture_object_id; |
| break; |
| case TEST_TEXTURE_TYPE_NO_STORAGE_ALLOCATED: |
| texture_object_id = test_run.parent_texture_object_id; |
| break; |
| case TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_IMMUTABLE_TEXTURE_OBJECT: |
| texture_object_id = test_run.texture_view_object_created_from_immutable_to_id; |
| break; |
| case TEST_TEXTURE_TYPE_TEXTURE_VIEW_CREATED_FROM_TEXTURE_VIEW: |
| texture_object_id = test_run.texture_view_object_created_from_view_to_id; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture type"); |
| } |
| } |
| |
| /* Bind the texture object of our interest to the target */ |
| gl.bindTexture(test_run.texture_target, texture_object_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| /* Run all the queries */ |
| gl.getTexParameterfv(test_run.texture_target, GL_TEXTURE_IMMUTABLE_LEVELS, |
| &query_texture_immutable_levels_value_float); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameterfv() failed for GL_TEXTURE_IMMUTABLE_LEVELS pname"); |
| |
| gl.getTexParameteriv(test_run.texture_target, GL_TEXTURE_IMMUTABLE_LEVELS, |
| &query_texture_immutable_levels_value_int); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexPrameteriv() failed for GL_TEXTURE_IMMUTABLE_LEVELS pname"); |
| |
| gl.getTexParameterfv(test_run.texture_target, GL_TEXTURE_VIEW_MIN_LAYER, |
| &query_texture_view_min_layer_value_float); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameterfv() failed for GL_TEXTURE_VIEW_MIN_LAYER pname"); |
| |
| gl.getTexParameteriv(test_run.texture_target, GL_TEXTURE_VIEW_MIN_LAYER, |
| &query_texture_view_min_layer_value_int); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_MIN_LAYER pname"); |
| |
| gl.getTexParameterfv(test_run.texture_target, GL_TEXTURE_VIEW_MIN_LEVEL, |
| &query_texture_view_min_level_value_float); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameterfv() failed for GL_TEXTURE_VIEW_MIN_LEVEL pname"); |
| |
| gl.getTexParameteriv(test_run.texture_target, GL_TEXTURE_VIEW_MIN_LEVEL, |
| &query_texture_view_min_level_value_int); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_MIN_LEVEL pname"); |
| |
| gl.getTexParameterfv(test_run.texture_target, GL_TEXTURE_VIEW_NUM_LAYERS, |
| &query_texture_view_num_layers_value_float); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameterfv() failed for GL_TEXTURE_VIEW_NUM_LAYERS pname"); |
| |
| gl.getTexParameteriv(test_run.texture_target, GL_TEXTURE_VIEW_NUM_LAYERS, |
| &query_texture_view_num_layers_value_int); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_NUM_LAYERS pname"); |
| |
| gl.getTexParameterfv(test_run.texture_target, GL_TEXTURE_VIEW_NUM_LEVELS, |
| &query_texture_view_num_levels_value_float); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameterfv() failed for GL_TEXTURE_VIEW_NUM_LEVELS pname"); |
| |
| gl.getTexParameteriv(test_run.texture_target, GL_TEXTURE_VIEW_NUM_LEVELS, |
| &query_texture_view_num_levels_value_int); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexParameteriv() failed for GL_TEXTURE_VIEW_NUM_LEVELS pname"); |
| |
| /* Verify the results */ |
| const float epsilon = 1e-5f; |
| |
| if (de::abs(query_texture_immutable_levels_value_float - (float)test_run.expected_n_immutable_levels) > epsilon) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid floating-point value reported for GL_TEXTURE_IMMUTABLE_LEVELS pname " |
| << "(expected: " << test_run.expected_n_immutable_levels |
| << " found: " << query_texture_immutable_levels_value_float << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_IMMUTABLE_LEVELS pname"); |
| } |
| |
| if (query_texture_immutable_levels_value_int != test_run.expected_n_immutable_levels) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid integer value reported for GL_TEXTURE_IMMUTABLE_LEVELS pname " |
| << "(expected: " << test_run.expected_n_immutable_levels |
| << " found: " << query_texture_immutable_levels_value_int << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_IMMUTABLE_LEVELS pname"); |
| } |
| |
| if (de::abs(query_texture_view_min_layer_value_float - (float)test_run.expected_n_min_layer) > epsilon) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid floating-point value reported for GL_TEXTURE_VIEW_MIN_LAYER pname " |
| << "(expected: " << test_run.expected_n_min_layer |
| << " found: " << query_texture_view_min_layer_value_float << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_MIN_LAYER pname"); |
| } |
| |
| if (query_texture_view_min_layer_value_int != test_run.expected_n_min_layer) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid integer value reported for GL_TEXTURE_VIEW_MIN_LAYER pname " |
| << "(expected: " << test_run.expected_n_min_layer |
| << " found: " << query_texture_view_min_layer_value_int << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_MIN_LAYER pname"); |
| } |
| |
| if (de::abs(query_texture_view_min_level_value_float - (float)test_run.expected_n_min_level) > epsilon) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid floating-point value reported for GL_TEXTURE_VIEW_MIN_LEVEL pname " |
| << "(expected: " << test_run.expected_n_min_level |
| << " found: " << query_texture_view_min_level_value_float << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_MIN_LEVEL pname"); |
| } |
| |
| if (query_texture_view_min_level_value_int != test_run.expected_n_min_level) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid integer value reported for GL_TEXTURE_VIEW_MIN_LEVEL pname " |
| << "(expected: " << test_run.expected_n_min_level |
| << " found: " << query_texture_view_min_level_value_int << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_MIN_LEVEL pname"); |
| } |
| |
| if (de::abs(query_texture_view_num_layers_value_float - (float)test_run.expected_n_num_layers) > epsilon) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid floating-point value reported for GL_TEXTURE_VIEW_NUM_LAYERS pname " |
| << "(expected: " << test_run.expected_n_num_layers |
| << " found: " << query_texture_view_num_layers_value_float << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_NUM_LAYERS pname"); |
| } |
| |
| if (query_texture_view_num_layers_value_int != test_run.expected_n_num_layers) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid integer value reported for GL_TEXTURE_VIEW_NUM_LAYERS pname " |
| << "(expected: " << test_run.expected_n_num_layers |
| << " found: " << query_texture_view_num_layers_value_int << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_NUM_LAYERS pname"); |
| } |
| |
| if (de::abs(query_texture_view_num_levels_value_float - (float)test_run.expected_n_num_levels) > epsilon) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid floating-point value reported for GL_TEXTURE_VIEW_NUM_LEVELS pname " |
| << "(expected: " << test_run.expected_n_num_levels |
| << " found: " << query_texture_view_num_levels_value_float << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_NUM_LEVELS pname"); |
| } |
| |
| if (query_texture_view_num_levels_value_int != test_run.expected_n_num_levels) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid integer value reported for GL_TEXTURE_VIEW_NUM_LEVELS pname " |
| << "(expected: " << test_run.expected_n_num_levels |
| << " found: " << query_texture_view_num_levels_value_int << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Invalid FP value reported for GL_TEXTURE_VIEW_NUM_LEVELS pname"); |
| } |
| } /* for (all test runs) */ |
| |
| /* Test case passed */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| **/ |
| TextureViewTestErrors::TextureViewTestErrors(deqp::Context& context) |
| : TestCase(context, "errors", "test_description") |
| , m_bo_id(0) |
| , m_reference_immutable_to_1d_id(0) |
| , m_reference_immutable_to_2d_id(0) |
| , m_reference_immutable_to_2d_array_id(0) |
| , m_reference_immutable_to_2d_array_32_by_33_id(0) |
| , m_reference_immutable_to_2d_multisample_id(0) |
| , m_reference_immutable_to_3d_id(0) |
| , m_reference_immutable_to_cube_map_id(0) |
| , m_reference_immutable_to_cube_map_array_id(0) |
| , m_reference_immutable_to_rectangle_id(0) |
| , m_reference_mutable_to_2d_id(0) |
| , m_test_modified_to_id_1(0) |
| , m_test_modified_to_id_2(0) |
| , m_test_modified_to_id_3(0) |
| , m_view_bound_to_id(0) |
| , m_view_never_bound_to_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all GL objects that may have been generated for the test. */ |
| void TextureViewTestErrors::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id); |
| |
| m_bo_id = 0; |
| } |
| |
| if (m_reference_immutable_to_1d_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_1d_id); |
| |
| m_reference_immutable_to_1d_id = 0; |
| } |
| |
| if (m_reference_immutable_to_2d_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_2d_id); |
| |
| m_reference_immutable_to_2d_id = 0; |
| } |
| |
| if (m_reference_immutable_to_2d_array_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_2d_array_id); |
| |
| m_reference_immutable_to_2d_array_id = 0; |
| } |
| |
| if (m_reference_immutable_to_2d_array_32_by_33_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_2d_array_32_by_33_id); |
| |
| m_reference_immutable_to_2d_array_32_by_33_id = 0; |
| } |
| |
| if (m_reference_immutable_to_2d_multisample_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_2d_multisample_id); |
| |
| m_reference_immutable_to_2d_multisample_id = 0; |
| } |
| |
| if (m_reference_immutable_to_3d_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_3d_id); |
| |
| m_reference_immutable_to_3d_id = 0; |
| } |
| |
| if (m_reference_immutable_to_cube_map_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_cube_map_id); |
| |
| m_reference_immutable_to_cube_map_id = 0; |
| } |
| |
| if (m_reference_immutable_to_cube_map_array_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_cube_map_array_id); |
| |
| m_reference_immutable_to_cube_map_array_id = 0; |
| } |
| |
| if (m_reference_immutable_to_rectangle_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_immutable_to_rectangle_id); |
| |
| m_reference_immutable_to_rectangle_id = 0; |
| } |
| |
| if (m_reference_mutable_to_2d_id != 0) |
| { |
| gl.deleteTextures(1, &m_reference_mutable_to_2d_id); |
| |
| m_reference_mutable_to_2d_id = 0; |
| } |
| |
| if (m_test_modified_to_id_1 != 0) |
| { |
| gl.deleteTextures(1, &m_test_modified_to_id_1); |
| |
| m_test_modified_to_id_1 = 0; |
| } |
| |
| if (m_test_modified_to_id_2 != 0) |
| { |
| gl.deleteTextures(1, &m_test_modified_to_id_2); |
| |
| m_test_modified_to_id_2 = 0; |
| } |
| |
| if (m_test_modified_to_id_3 != 0) |
| { |
| gl.deleteTextures(1, &m_test_modified_to_id_3); |
| |
| m_test_modified_to_id_3 = 0; |
| } |
| |
| if (m_view_bound_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_bound_to_id); |
| |
| m_view_bound_to_id = 0; |
| } |
| |
| if (m_view_never_bound_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_never_bound_to_id); |
| |
| m_view_never_bound_to_id = 0; |
| } |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestErrors::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Make sure GL_ARB_texture_view is reported as supported before carrying on |
| * with actual execution */ |
| const std::vector<std::string>& extensions = m_context.getContextInfo().getExtensions(); |
| |
| if (std::find(extensions.begin(), extensions.end(), "GL_ARB_texture_view") == extensions.end()) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported"); |
| } |
| |
| /* Create a buffer object that we'll need to use to define storage of |
| * buffer textures */ |
| gl.genBuffers(1, &m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed"); |
| |
| gl.bindBuffer(GL_TEXTURE_BUFFER, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed"); |
| |
| gl.bufferData(GL_TEXTURE_BUFFER, 123, /* arbitrary size */ |
| DE_NULL, /* data */ |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed"); |
| |
| /* Create reference texture objects */ |
| const glw::GLint reference_bo_id = m_bo_id; |
| const glw::GLint reference_to_depth = 2; |
| const glw::GLenum reference_to_format = GL_RGBA; |
| const glw::GLint reference_to_height = 64; |
| const glw::GLenum reference_to_internalformat = GL_RGBA32F; |
| const glw::GLint reference_n_cubemaps = 1; |
| const glw::GLint reference_n_levels = 1; |
| const glw::GLenum reference_to_type = GL_FLOAT; |
| const glw::GLint reference_to_width = 64; |
| |
| gl.genTextures(1, &m_reference_immutable_to_1d_id); |
| gl.genTextures(1, &m_reference_immutable_to_2d_id); |
| gl.genTextures(1, &m_reference_immutable_to_2d_array_id); |
| gl.genTextures(1, &m_reference_immutable_to_2d_array_32_by_33_id); |
| gl.genTextures(1, &m_reference_immutable_to_2d_multisample_id); |
| gl.genTextures(1, &m_reference_immutable_to_3d_id); |
| gl.genTextures(1, &m_reference_immutable_to_cube_map_id); |
| gl.genTextures(1, &m_reference_immutable_to_cube_map_array_id); |
| gl.genTextures(1, &m_reference_immutable_to_rectangle_id); |
| gl.genTextures(1, &m_reference_mutable_to_2d_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed"); |
| |
| /* Retrieve GL_SAMPLES value - we'll need it to initialize multisample storage */ |
| glw::GLint gl_max_samples_value = 0; |
| |
| gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, reference_to_internalformat, GL_SAMPLES, |
| 1 /* bufSize - first result */, &gl_max_samples_value); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_SAMPLES pname"); |
| |
| /* Set up texture storage for single-dimensional texture object */ |
| gl.bindTexture(GL_TEXTURE_1D, m_reference_immutable_to_1d_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage1D(GL_TEXTURE_1D, reference_n_levels, reference_to_internalformat, reference_to_width); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage1D() call failed"); |
| |
| /* Set up immutable texture storage for two-dimensional texture object */ |
| gl.bindTexture(GL_TEXTURE_2D, m_reference_immutable_to_2d_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, reference_n_levels, reference_to_internalformat, reference_to_width, |
| reference_to_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| |
| /* Set up immutable texture storage for two-dimensional array texture object */ |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_reference_immutable_to_2d_array_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage3D(GL_TEXTURE_2D_ARRAY, reference_n_levels, reference_to_internalformat, reference_to_width, |
| reference_to_height, reference_to_depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed"); |
| |
| /* Set up immutable texture storage for two-dimensional array texture object, base |
| * level of which uses a resolution of 32x33. We'll need it to check case r) */ |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_reference_immutable_to_2d_array_32_by_33_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage3D(GL_TEXTURE_2D_ARRAY, reference_n_levels, reference_to_internalformat, 32, /* width */ |
| 33, /* height */ |
| 6); /* depth - 6 layers so that a cube-map/cube-map array view can be created from this texture */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed"); |
| |
| /* Set up immutable texture storage for two-dimensional multisample texture object */ |
| gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_reference_immutable_to_2d_multisample_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, gl_max_samples_value, reference_to_internalformat, |
| reference_to_width, reference_to_height, GL_TRUE); /* fixedsamplelocations */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2DMultisample() call failed"); |
| |
| /* Set up immutable texture storage for three-dimensional texture object */ |
| gl.bindTexture(GL_TEXTURE_3D, m_reference_immutable_to_3d_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage3D(GL_TEXTURE_3D, reference_n_levels, reference_to_internalformat, reference_to_width, |
| reference_to_height, reference_to_depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed"); |
| |
| /* Set up immutable texture storage for cube-map texture object */ |
| gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_reference_immutable_to_cube_map_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2D(GL_TEXTURE_CUBE_MAP, reference_n_levels, reference_to_internalformat, reference_to_width, |
| reference_to_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| |
| /* Set up immutable texture storage for cube-map array texture object */ |
| gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_reference_immutable_to_cube_map_array_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, reference_n_levels, reference_to_internalformat, reference_to_width, |
| reference_to_height, 6 /* layer-faces */ * reference_to_depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| |
| /* Set up immutable texture storage for rectangular texture object */ |
| gl.bindTexture(GL_TEXTURE_RECTANGLE, m_reference_immutable_to_rectangle_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2D(GL_TEXTURE_RECTANGLE, reference_n_levels, reference_to_internalformat, reference_to_width, |
| reference_to_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| |
| /* Set up mutable texture storage for two-dimensional texture object */ |
| gl.bindTexture(GL_TEXTURE_2D, m_reference_mutable_to_2d_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| for (glw::GLint n_level = 0; n_level < reference_n_levels; ++n_level) |
| { |
| gl.texImage2D(GL_TEXTURE_2D, n_level, reference_to_internalformat, reference_to_width << n_level, |
| reference_to_height << n_level, 0, /* border */ |
| reference_to_format, reference_to_type, DE_NULL); /* pixels */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D() call failed"); |
| } |
| |
| /* Create texture objects we'll be attempting to define as texture views */ |
| gl.genTextures(1, &m_view_bound_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed"); |
| |
| gl.genTextures(1, &m_view_never_bound_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_view_bound_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| /* a) GL_INVALID_VALUE should be generated if <texture> is 0. */ |
| glw::GLint error_code = GL_NO_ERROR; |
| |
| gl.textureView(0, /* texture */ |
| GL_TEXTURE_2D, m_reference_immutable_to_2d_id, reference_to_internalformat, 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <texture> argument of 0" |
| " to a glTextureView(), whereas GL_INVALID_VALUE was " |
| "expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing 0 as <texture> argument to a " |
| "glTextureView() call."); |
| } |
| |
| /* b) GL_INVALID_OPERATION should be generated if <texture> is not |
| * a valid name returned by glGenTextures(). |
| */ |
| const glw::GLint invalid_to_id = 0xFFFFFFFF; |
| |
| gl.textureView(invalid_to_id, GL_TEXTURE_2D, m_reference_immutable_to_2d_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <texture> argument of" |
| " value that does not correspond to a valid texture " |
| "object ID, whereas GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when passing 0xFFFFFFFF as <texture> " |
| "argument to a glTextureView() call."); |
| } |
| |
| /* c) GL_INVALID_OPERATION should be generated if <texture> has |
| * already been bound and given a target. |
| */ |
| gl.textureView(m_view_bound_to_id, GL_TEXTURE_2D, m_reference_immutable_to_2d_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <texture> argument " |
| " that refers to an ID of a texture object that has " |
| "already been bound to a texture target, whereas " |
| "GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when passing <texture> set" |
| " to an ID of a texture object, that has already been bound to" |
| " a texture target, to a glTextureView() call."); |
| } |
| |
| /* d) GL_INVALID_VALUE should be generated if <origtexture> is not |
| * the name of a texture object. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_2D, invalid_to_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <origtexture> argument " |
| " of value 0xFFFFFFFF, whereas GL_INVALID_VALUE was " |
| "expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing an invalid ID of a texture " |
| "object to <origtexture> argument."); |
| } |
| |
| /* e) GL_INVALID_OPERATION error should be generated if <origtexture> |
| * is a mutable texture object. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_2D, m_reference_mutable_to_2d_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <origtexture> argument " |
| " set to refer to a mutable texture object, whereas " |
| "GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when passing an ID of a mutable " |
| "texture object through <origtexture> argument."); |
| } |
| |
| /* f) GL_INVALID_OPERATION error should be generated whenever the |
| * application tries to generate a texture view for a target |
| * that is incompatible with original texture's target. (as per |
| * table 8.20 from OpenGL 4.3 specification) |
| * |
| * NOTE: All invalid original+view texture target combinations |
| * should be checked. |
| */ |
| TextureViewUtilities::_incompatible_texture_target_pairs incompatible_texture_target_pairs = |
| TextureViewUtilities::getIllegalTextureAndViewTargetCombinations(); |
| |
| for (TextureViewUtilities::_incompatible_texture_target_pairs_const_iterator pair_iterator = |
| incompatible_texture_target_pairs.begin(); |
| pair_iterator != incompatible_texture_target_pairs.end(); pair_iterator++) |
| { |
| TextureViewUtilities::_internalformat_pair texture_target_pair = *pair_iterator; |
| glw::GLenum original_texture_target = texture_target_pair.first; |
| glw::GLenum view_texture_target = texture_target_pair.second; |
| |
| /* Generate texture IDs */ |
| gl.genTextures(1, &m_test_modified_to_id_1); |
| gl.genTextures(1, &m_test_modified_to_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed"); |
| |
| /* Configure reference texture object storage */ |
| gl.bindTexture(original_texture_target, m_test_modified_to_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| TextureViewUtilities::initTextureStorage(gl, true, /* create mutable parent texture */ |
| original_texture_target, reference_to_depth, reference_to_height, |
| reference_to_width, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, |
| reference_n_levels, reference_n_cubemaps, reference_bo_id); |
| |
| /* Attempt to create the invalid view */ |
| gl.textureView(m_test_modified_to_id_2, /* texture */ |
| view_texture_target, m_test_modified_to_id_1, /* origtexture */ |
| reference_to_internalformat, 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <origtexture> argument " |
| " set to refer to a mutable texture object, whereas " |
| "GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when passing an ID of a mutable " |
| "texture object through <origtexture> argument."); |
| } |
| |
| /* Release the texture IDs */ |
| gl.deleteTextures(1, &m_test_modified_to_id_1); |
| m_test_modified_to_id_1 = 0; |
| |
| gl.deleteTextures(1, &m_test_modified_to_id_2); |
| m_test_modified_to_id_2 = 0; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call(s) failed"); |
| } /* for (all incompatible texture target pairs) */ |
| |
| /* g) GL_INVALID_OPERATION error should be generated whenever the |
| * application tries to create a texture view, internal format |
| * of which can be found in table 8.21 of OpenGL 4.4 |
| * specification, and the texture view's internal format is |
| * incompatible with parent object's internal format. Both |
| * textures and views should be used as parent objects for the |
| * purpose of the test. |
| * |
| * NOTE: All invalid texture view internal formats should be |
| * checked for all applicable original object's internal |
| * formats |
| */ |
| glw::GLint context_major_version = 0; |
| glw::GLint context_minor_version = 0; |
| |
| TextureViewUtilities::getMajorMinorVersionFromContextVersion(m_context.getRenderContext().getType(), |
| &context_major_version, &context_minor_version); |
| |
| TextureViewUtilities::_incompatible_internalformat_pairs internalformat_pairs = |
| TextureViewUtilities::getIllegalTextureAndViewInternalformatCombinations(); |
| |
| for (TextureViewUtilities::_incompatible_internalformat_pairs::const_iterator pair_iterator = |
| internalformat_pairs.begin(); |
| pair_iterator != internalformat_pairs.end(); pair_iterator++) |
| { |
| glw::GLenum src_internalformat = pair_iterator->first; |
| glw::GLenum view_internalformat = pair_iterator->second; |
| |
| /* Only run the test for internalformats supported by the tested OpenGL implementation */ |
| if (!TextureViewUtilities::isInternalformatSupported(src_internalformat, context_major_version, |
| context_minor_version) || |
| !TextureViewUtilities::isInternalformatSupported(view_internalformat, context_major_version, |
| context_minor_version)) |
| { |
| /* Next iteration, please */ |
| continue; |
| } |
| |
| /* Generate texture IDs */ |
| gl.genTextures(1, &m_test_modified_to_id_1); |
| gl.genTextures(1, &m_test_modified_to_id_2); |
| gl.genTextures(1, &m_test_modified_to_id_3); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed"); |
| |
| /* Configure reference texture object storage */ |
| gl.bindTexture(GL_TEXTURE_2D, m_test_modified_to_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| TextureViewUtilities::initTextureStorage( |
| gl, false, /* views require immutable parent texture objects */ |
| GL_TEXTURE_2D, 0, /* texture_depth */ |
| reference_to_height, reference_to_width, src_internalformat, |
| GL_NONE, /* texture_format - not needed for immutable texture objects */ |
| GL_NONE, /* texture_type - not needed for immutable texture objects */ |
| reference_n_levels, 0, /* n_cubemaps_needed */ |
| 0); /* bo_id */ |
| |
| /* Attempt to create an invalid view */ |
| gl.textureView(m_test_modified_to_id_2, /* texture */ |
| GL_TEXTURE_2D, m_test_modified_to_id_1, /* origtexture */ |
| view_internalformat, 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when requesting a view that uses " |
| " an internalformat that is incompatible with parent " |
| " texture object's, whereas GL_INVALID_OPERATION was " |
| "expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when requesting a texture view that " |
| "uses an internalformat which is incompatible with parent texture's."); |
| } |
| |
| /* Create a valid view now */ |
| gl.textureView(m_test_modified_to_id_2, /* texture */ |
| GL_TEXTURE_2D, m_test_modified_to_id_1, /* origtexture */ |
| src_internalformat, 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "A valid glTextureView() call failed"); |
| |
| /* Attempt to create an invalid view, using the view we've just created |
| * as a parent */ |
| gl.textureView(m_test_modified_to_id_3, /* texture */ |
| GL_TEXTURE_2D, m_test_modified_to_id_2, /* origtexture */ |
| view_internalformat, 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when requesting a view that uses " |
| " an internalformat that is incompatible with parent " |
| " view's, whereas GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when requesting a texture view that " |
| "uses an internalformat which is incompatible with parent view's."); |
| } |
| |
| /* Release the texture IDs */ |
| gl.deleteTextures(1, &m_test_modified_to_id_1); |
| m_test_modified_to_id_1 = 0; |
| |
| gl.deleteTextures(1, &m_test_modified_to_id_2); |
| m_test_modified_to_id_2 = 0; |
| |
| gl.deleteTextures(1, &m_test_modified_to_id_3); |
| m_test_modified_to_id_3 = 0; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call(s) failed"); |
| } /* for (all incompatible texture+view internalformat pairs) */ |
| |
| /* h) GL_INVALID_OPERATION error should be generated whenever the |
| * application tries to create a texture view using an internal |
| * format that does not match the original texture's, and the |
| * original texture's internalformat cannot be found in table |
| * 8.21 of OpenGL 4.3 specification. |
| * |
| * NOTE: All required base, sized and compressed texture internal |
| * formats (as described in section 8.5.1 and table 8.14 |
| * of OpenGL 4.3 specification) that cannot be found in |
| * table 8.21 should be considered for the purpose of this |
| * test. |
| */ |
| for (int n_gl_internalformat = 0; n_gl_internalformat < n_valid_gl_internalformats; ++n_gl_internalformat) |
| { |
| glw::GLenum parent_texture_internalformat = valid_gl_internalformats[n_gl_internalformat]; |
| |
| /* Only run the test for internalformats supported by the tested OpenGL implementation */ |
| if (!TextureViewUtilities::isInternalformatSupported(parent_texture_internalformat, context_major_version, |
| context_minor_version)) |
| { |
| /* Iterate the loop */ |
| continue; |
| } |
| |
| /* For the purpose of the test, only consider internalformats that |
| * are not associated with any view class */ |
| if (TextureViewUtilities::getViewClassForInternalformat(parent_texture_internalformat) == VIEW_CLASS_UNDEFINED) |
| { |
| /* Initialize parent texture object */ |
| gl.genTextures(1, &m_test_modified_to_id_1); |
| gl.genTextures(1, &m_test_modified_to_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed"); |
| |
| /* Configure reference texture object storage */ |
| gl.bindTexture(GL_TEXTURE_2D, m_test_modified_to_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| TextureViewUtilities::initTextureStorage( |
| gl, false, /* views require immutable parent texture objects */ |
| GL_TEXTURE_2D, 0, /* texture_depth */ |
| reference_to_height, reference_to_width, parent_texture_internalformat, |
| GL_NONE, /* texture_format - not needed for immutable texture objects */ |
| GL_NONE, /* texture_type - not needed for immutable texture objects */ |
| reference_n_levels, 0, /* n_cubemaps_needed */ |
| 0); /* bo_id */ |
| |
| /* Attempt to create the invalid view */ |
| gl.textureView(m_test_modified_to_id_2, /* texture */ |
| GL_TEXTURE_2D, m_test_modified_to_id_1, /* origtexture */ |
| (parent_texture_internalformat != GL_RGBA32F) ? GL_RGBA32F : GL_RGB32F, 0, /* minlevel */ |
| reference_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" |
| << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when requesting a view that uses " |
| " an internalformat different than the one used by " |
| "parent texture object: " |
| "[" |
| << parent_texture_internalformat |
| << "] " |
| " and the parent texture's internalformat is not " |
| "associated with any view class; GL_INVALID_OPERATION " |
| "was expected" |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when requesting a texture view for " |
| "a parent texture, internalformat of which is not associated with any " |
| "view class, when the view's internalformat is different than the one " |
| "used for parent texture."); |
| } |
| |
| /* Release the texture IDs */ |
| gl.deleteTextures(1, &m_test_modified_to_id_1); |
| m_test_modified_to_id_1 = 0; |
| |
| gl.deleteTextures(1, &m_test_modified_to_id_2); |
| m_test_modified_to_id_2 = 0; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call(s) failed"); |
| } /* if (parent texture internalformat is not associated with a view class) */ |
| } /* for (all valid GL internalformats) */ |
| |
| /* i) GL_INVALID_VALUE error should be generated if <minlevel> is |
| * larger than the greatest level of <origtexture>. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_2D, m_reference_immutable_to_2d_id, reference_to_internalformat, |
| reference_n_levels, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <minlevel> argument " |
| " larger than the greatest level of <origtexture>, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of <minlevel> " |
| "larger than the greatest level defined for <origtexture>"); |
| } |
| |
| /* j) GL_INVALID_VALUE error should be generated if <minlayer> is |
| * larger than the greatest layer of <origtexture>. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_2D_ARRAY, m_reference_immutable_to_2d_array_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| reference_n_levels, /* numlevels */ |
| reference_to_depth, /* minlayer */ |
| 1); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <minlayer> argument " |
| " larger than the greatest layer of <origtexture>, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of <minlayer> " |
| "larger than the greatest layer defined for <origtexture>"); |
| } |
| |
| /* k) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_CUBE_MAP and <numlayers> is not 6. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_CUBE_MAP, m_reference_immutable_to_cube_map_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 5); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "5 instead of 6 for GL_TEXTURE_CUBE_MAP texture target, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 5 to <minlayer>" |
| "argument"); |
| } |
| |
| /* l) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_CUBE_MAP_ARRAY and <numlayers> is not a multiple |
| * of 6. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_CUBE_MAP_ARRAY, m_reference_immutable_to_cube_map_array_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 1); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "1 instead of a multiple of 6 for GL_TEXTURE_CUBE_MAP_ARRAY " |
| "texture target, whereas GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 1 to <minlayer>" |
| "argument for a GL_TEXTURE_CUBE_MAP_ARRAY texture target"); |
| } |
| |
| /* m) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_1D and <numlayers> is not 1; |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_1D, m_reference_immutable_to_1d_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 2); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "2 instead of 1 for GL_TEXTURE_1D texture target, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 2 to <numlayers>" |
| "argument for a GL_TEXTURE_1D texture target"); |
| } |
| |
| /* n) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_2D and <numlayers> is not 1; |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_2D, m_reference_immutable_to_2d_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 2); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "2 instead of 1 for GL_TEXTURE_2D texture target, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 2 to <numlayers>" |
| "argument for a GL_TEXTURE_2D texture target"); |
| } |
| |
| /* o) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_3D and <numlayers> is not 1; |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_3D, m_reference_immutable_to_3d_id, reference_to_internalformat, |
| 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 2); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "2 instead of 1 for GL_TEXTURE_3D texture target, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 2 to <numlayers>" |
| "argument for a GL_TEXTURE_3D texture target"); |
| } |
| |
| /* p) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_RECTANGLE and <numlayers> is not 1; |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_RECTANGLE, m_reference_immutable_to_rectangle_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 2); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "2 instead of 1 for GL_TEXTURE_RECTANGLE texture target, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 2 to <numlayers>" |
| "argument for a GL_TEXTURE_RECTANGLE texture target"); |
| } |
| |
| /* q) GL_INVALID_VALUE error should be generated if <target> is |
| * GL_TEXTURE_2D_MULTISAMPLE and <numlayers> is not 1; |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_2D_MULTISAMPLE, m_reference_immutable_to_2d_multisample_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 2); /* numlayers - invalid argument value */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_VALUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when passing <numlayers> argument of value " |
| "2 instead of 1 for GL_TEXTURE_2D_MULTISAMPLE texture target, whereas " |
| "GL_INVALID_VALUE was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_VALUE not generated when passing a value of 2 to <numlayers>" |
| "argument for a GL_TEXTURE_2D_MULTISAMPLE texture target"); |
| } |
| |
| /* r) GL_INVALID_OPERATION error should be generated if <target> is |
| * GL_TEXTURE_CUBE_MAP and original texture's width does not |
| * match original texture's height for all levels. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_CUBE_MAP, m_reference_immutable_to_2d_array_32_by_33_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 6); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when using an immutable 2D array texture of 32x33x6 " |
| "resolution to generate a GL_TEXTURE_CUBE_MAP view, whereas " |
| "GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when using an immutable 2D array texture of " |
| "32x33x6 resolution to generate a GL_TEXTURE_CUBE_MAP view"); |
| } |
| |
| /* s) GL_INVALID_OPERATION error should be generated if <target> is |
| * GL_TEXTURE_CUBE_MAP_ARRAY and original texture's width does |
| * not match original texture's height for all levels. |
| */ |
| gl.textureView(m_view_never_bound_to_id, GL_TEXTURE_CUBE_MAP_ARRAY, m_reference_immutable_to_2d_array_32_by_33_id, |
| reference_to_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 6); /* numlayers */ |
| |
| error_code = gl.getError(); |
| if (error_code != GL_INVALID_OPERATION) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "[" << TextureViewUtilities::getErrorCodeString(error_code) |
| << "]" |
| " error generated when using an immutable 2D array texture of 32x33x6 " |
| "resolution to generate a GL_TEXTURE_CUBE_MAP_ARRAY view, whereas " |
| "GL_INVALID_OPERATION was expected." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("GL_INVALID_OPERATION not generated when using an immutable 2D array texture of " |
| "32x33x6 resolution to generate a GL_TEXTURE_CUBE_MAP_ARRAY view"); |
| } |
| |
| /* Test case passed */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| **/ |
| TextureViewTestViewSampling::TextureViewTestViewSampling(deqp::Context& context) |
| : TestCase(context, "view_sampling", "Verify that sampling data from texture views, that use internal " |
| "format which is compatible with the original texture's internal " |
| "format, works correctly.") |
| , m_bo_id(0) |
| , m_fs_id(0) |
| , m_gs_id(0) |
| , m_po_id(0) |
| , m_po_lod_location(-1) |
| , m_po_n_face_location(-1) |
| , m_po_reference_colors_location(-1) |
| , m_po_texture_location(-1) |
| , m_po_z_float_location(-1) |
| , m_po_z_int_location(-1) |
| , m_tc_id(0) |
| , m_te_id(0) |
| , m_vs_id(0) |
| , m_per_sample_filler_fs_id(0) |
| , m_per_sample_filler_gs_id(0) |
| , m_per_sample_filler_po_id(0) |
| , m_per_sample_filler_po_layer_id_location(-1) |
| , m_per_sample_filler_po_reference_colors_location(-1) |
| , m_per_sample_filler_vs_id(0) |
| , m_result_to_id(0) |
| , m_to_id(0) |
| , m_view_to_id(0) |
| , m_fbo_id(0) |
| , m_vao_id(0) |
| , m_max_color_texture_samples_gl_value(0) |
| , m_iteration_parent_texture_depth(0) |
| , m_iteration_parent_texture_height(0) |
| , m_iteration_parent_texture_n_levels(0) |
| , m_iteration_parent_texture_n_samples(0) |
| , m_iteration_parent_texture_target(GL_NONE) |
| , m_iteration_parent_texture_width(0) |
| , m_iteration_view_texture_minlayer(0) |
| , m_iteration_view_texture_numlayers(0) |
| , m_iteration_view_texture_minlevel(0) |
| , m_iteration_view_texture_numlevels(0) |
| , m_iteration_view_texture_target(GL_NONE) |
| , m_reference_texture_depth(4) |
| , m_reference_texture_height(4) |
| , m_reference_texture_n_mipmaps(3) |
| , m_reference_texture_width(4) |
| , m_reference_color_storage(DE_NULL) |
| , m_result_data(DE_NULL) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** De-initializes all GL objects created for the test. */ |
| void TextureViewTestViewSampling::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| deinitIterationSpecificProgramAndShaderObjects(); |
| deinitPerSampleFillerProgramAndShaderObjects(); |
| deinitTextureObjects(); |
| |
| /* Make sure any buffers we may have allocated during the execution do not leak */ |
| if (m_result_data != DE_NULL) |
| { |
| delete[] m_result_data; |
| |
| m_result_data = DE_NULL; |
| } |
| |
| /* Deinitialize other objects that are not re-created every iteration */ |
| if (m_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id); |
| |
| m_bo_id = 0; |
| } |
| |
| if (m_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| |
| m_fbo_id = 0; |
| } |
| |
| if (m_reference_color_storage != DE_NULL) |
| { |
| delete m_reference_color_storage; |
| |
| m_reference_color_storage = DE_NULL; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| |
| /* Restore default GL state the test may have modified */ |
| gl.patchParameteri(GL_PATCH_VERTICES, 3); |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 4); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); |
| } |
| |
| /** De-initializes program and shader objects created for each iteration. **/ |
| void TextureViewTestViewSampling::deinitIterationSpecificProgramAndShaderObjects() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| |
| m_fs_id = 0; |
| } |
| |
| if (m_gs_id != 0) |
| { |
| gl.deleteShader(m_gs_id); |
| |
| m_gs_id = 0; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| |
| if (m_tc_id != 0) |
| { |
| gl.deleteShader(m_tc_id); |
| |
| m_tc_id = 0; |
| } |
| |
| if (m_te_id != 0) |
| { |
| gl.deleteShader(m_te_id); |
| |
| m_te_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /** De-initializes shader and program objects providing the 'per-sample filling' |
| * functionality. |
| **/ |
| void TextureViewTestViewSampling::deinitPerSampleFillerProgramAndShaderObjects() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_per_sample_filler_fs_id != 0) |
| { |
| gl.deleteShader(m_per_sample_filler_fs_id); |
| |
| m_per_sample_filler_fs_id = 0; |
| } |
| |
| if (m_per_sample_filler_gs_id != 0) |
| { |
| gl.deleteShader(m_per_sample_filler_gs_id); |
| |
| m_per_sample_filler_gs_id = 0; |
| } |
| |
| if (m_per_sample_filler_po_id != 0) |
| { |
| gl.deleteProgram(m_per_sample_filler_po_id); |
| |
| m_per_sample_filler_po_id = 0; |
| } |
| |
| if (m_per_sample_filler_vs_id != 0) |
| { |
| gl.deleteShader(m_per_sample_filler_vs_id); |
| |
| m_per_sample_filler_vs_id = 0; |
| } |
| } |
| |
| /** De-initializes texture objects used by the test */ |
| void TextureViewTestViewSampling::deinitTextureObjects() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_result_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_result_to_id); |
| |
| m_result_to_id = 0; |
| } |
| |
| if (m_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| |
| m_to_id = 0; |
| } |
| |
| if (m_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_to_id); |
| |
| m_view_to_id = 0; |
| } |
| } |
| |
| /** Executes a single test iteration. |
| * |
| * @return true if the iteration executed successfully, false otherwise. |
| **/ |
| bool TextureViewTestViewSampling::executeTest() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Bind the view to zero texture unit */ |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed."); |
| |
| gl.bindTexture(m_iteration_view_texture_target, m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Bind the buffer object to zero TF binding point */ |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed."); |
| |
| /* Activate the test program */ |
| gl.useProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| /* Update draw framebuffer configuration so that the test's fragment shader draws |
| * to the result texture */ |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); |
| |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_result_to_id, 0); /* level */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); |
| |
| /* Allocate enough space to hold reference color data for all sample s*/ |
| float* reference_color_data = new float[m_iteration_parent_texture_n_samples * sizeof(float) * 4 /* rgba */]; |
| |
| /* Iterate through the layer/face/mipmap hierarchy. For each iteration, we |
| * potentially need to update relevant uniforms controlling the sampling process |
| * the test program object performs. |
| */ |
| bool is_view_cm_cma = (m_iteration_view_texture_target == GL_TEXTURE_CUBE_MAP || |
| m_iteration_view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| |
| for (unsigned int n_current_layer = m_iteration_view_texture_minlayer; |
| n_current_layer < (m_iteration_view_texture_minlayer + m_iteration_view_texture_numlayers) && result; |
| n_current_layer++) |
| { |
| unsigned int n_texture_face = 0; |
| unsigned int n_texture_layer = 0; |
| unsigned int n_view_face = 0; |
| unsigned int n_view_layer = 0; |
| |
| if (is_view_cm_cma) |
| { |
| n_texture_face = n_current_layer % 6; /* faces */ |
| n_texture_layer = n_current_layer / 6; /* faces */ |
| n_view_face = (n_current_layer - m_iteration_view_texture_minlayer) % 6; /* faces */ |
| n_view_layer = (n_current_layer - m_iteration_view_texture_minlayer) / 6; /* faces */ |
| } |
| else |
| { |
| /* Only cube-map and cube-map array textures consist of faces. */ |
| n_texture_face = 0; |
| n_texture_layer = n_current_layer; |
| n_view_face = 0; |
| n_view_layer = n_current_layer; |
| } |
| |
| if (m_po_z_float_location != -1) |
| { |
| float z = 0.0f; |
| |
| if (((false == is_view_cm_cma) && (m_iteration_view_texture_numlayers > 1)) || |
| ((true == is_view_cm_cma) && (m_iteration_view_texture_numlayers > 6))) |
| { |
| if (is_view_cm_cma) |
| { |
| z = float(n_view_layer) / float(m_iteration_view_texture_numlayers / 6 - 1); |
| } |
| else |
| { |
| if (m_iteration_view_texture_numlayers > 1) |
| { |
| /* The program will be sampling a view so make sure that layer the shader accesses |
| * is relative to how our view was configured */ |
| z = float(n_view_layer - m_iteration_view_texture_minlayer) / |
| float(m_iteration_view_texture_numlayers - 1); |
| } |
| else |
| { |
| /* z should stay at 0 */ |
| } |
| } |
| } |
| else |
| { |
| /* z should stay at 0.0 */ |
| } |
| |
| gl.uniform1f(m_po_z_float_location, z); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1f() call failed."); |
| } |
| |
| if (m_po_z_int_location != -1) |
| { |
| DE_ASSERT(!is_view_cm_cma); |
| |
| gl.uniform1i(m_po_z_int_location, n_current_layer - m_iteration_view_texture_minlayer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| } |
| |
| if (m_po_n_face_location != -1) |
| { |
| gl.uniform1i(m_po_n_face_location, n_view_face); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| } |
| |
| for (unsigned int n_mipmap = m_iteration_view_texture_minlevel; |
| n_mipmap < (m_iteration_view_texture_minlevel + m_iteration_view_texture_numlevels) && result; n_mipmap++) |
| { |
| if (m_po_lod_location != -1) |
| { |
| /* The program will be sampling a view so make sure that LOD the shader accesses |
| * is relative to how our view was configured. |
| */ |
| gl.uniform1f(m_po_lod_location, (float)(n_mipmap - m_iteration_view_texture_minlevel)); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| } |
| |
| /* Update local reference color data storage */ |
| for (unsigned int n_sample = 0; n_sample < m_iteration_parent_texture_n_samples; ++n_sample) |
| { |
| tcu::Vec4 reference_color = getReferenceColor(n_texture_layer, n_texture_face, n_mipmap, n_sample); |
| |
| reference_color_data[4 /* rgba */ * n_sample + 0] = reference_color.x(); |
| reference_color_data[4 /* rgba */ * n_sample + 1] = reference_color.y(); |
| reference_color_data[4 /* rgba */ * n_sample + 2] = reference_color.z(); |
| reference_color_data[4 /* rgba */ * n_sample + 3] = reference_color.w(); |
| } |
| |
| /* Upload it to GPU */ |
| gl.uniform4fv(m_po_reference_colors_location, m_iteration_parent_texture_n_samples, reference_color_data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed."); |
| |
| /* Bind the texture view to sample from */ |
| gl.bindTexture(m_iteration_view_texture_target, m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Draw a single patch. Given the rendering pipeline we've defined in the |
| * test program object, this should give us a nice full-screen quad, as well |
| * as 6*4 ints XFBed out, describing whether the view was sampled correctly. |
| */ |
| gl.beginTransformFeedback(GL_TRIANGLES); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); |
| { |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); |
| |
| /* In order to verify if the texel data was sampled correctly, we need to do two things: |
| * |
| * 1) Verify buffer object contents; |
| * 2) Make sure that all texels of current render-target are vec4(1). |
| * |
| */ |
| const int* bo_storage_ptr = (const int*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed."); |
| if (bo_storage_ptr == NULL) |
| { |
| TCU_FAIL("glMapBuffer() call succeeded but the pointer returned is NULL"); |
| } |
| |
| /* The rendering pipeline should have written 6 vertices * 4 ints to the BO. |
| * The integers are set to 1 if the sampled texels were found valid, 0 otherwise, |
| * and are arranged in the following order: |
| * |
| * 1) Result of sampling in vertex shader stage; |
| * 2) Result of sampling in tessellation control shader stage; |
| * 3) Result of sampling in tessellation evaluation shader stage; |
| * 4) Result of sampling in geometry shader stage; |
| */ |
| for (unsigned int n_vertex = 0; n_vertex < 6 /* as per comment */ && result; ++n_vertex) |
| { |
| const int* vertex_data_ptr = bo_storage_ptr + n_vertex * 4 /* as per comment */; |
| int vs_result = vertex_data_ptr[0]; |
| int tc_result = vertex_data_ptr[1]; |
| int te_result = vertex_data_ptr[2]; |
| int gs_result = vertex_data_ptr[3]; |
| |
| if (vs_result != 1) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data was sampled in vertex shader stage." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| if (tc_result != 1) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid data was sampled in tessellation control shader stage." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| if (te_result != 1) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Invalid data was sampled in tessellation evaluation shader stage." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| if (gs_result != 1) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data was sampled in geometry shader stage." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| } /* for (all vertices) */ |
| |
| /* Unmap the BO */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); |
| |
| /* Read texels rendered by the fragment shader. The texture attached uses |
| * GL_RGBA8 internalformat.*/ |
| m_result_data = new unsigned char[m_reference_texture_width * m_reference_texture_height * 4 /* RGBA */]; |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_result_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed for GL_TEXTURE_2D texture target."); |
| |
| gl.getTexImage(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, GL_UNSIGNED_BYTE, m_result_data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexImage() call failed."); |
| |
| /* The test fails if any of the fragments is not equal to vec4(1) */ |
| bool fs_result = true; |
| |
| for (unsigned int y = 0; y < m_reference_texture_height && fs_result; ++y) |
| { |
| const unsigned char* row_ptr = m_result_data + m_reference_texture_width * y * 4 /* RGBA */; |
| |
| for (unsigned int x = 0; x < m_reference_texture_width && fs_result; ++x) |
| { |
| const unsigned char* pixel_ptr = row_ptr + x * 4 /* RGBA */; |
| |
| if (pixel_ptr[0] != 255 || pixel_ptr[1] != 255 || pixel_ptr[2] != 255 || pixel_ptr[3] != 255) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data was sampled at (" << x << ", " << y |
| << ") " |
| "in fragment shader stage." |
| << tcu::TestLog::EndMessage; |
| |
| fs_result = false; |
| } |
| } /* for (all columns) */ |
| } /* for (all rows) */ |
| |
| if (!fs_result) |
| { |
| result = false; |
| } |
| |
| /* Done - we can release the buffer at this point */ |
| delete[] m_result_data; |
| m_result_data = DE_NULL; |
| } /* for (all mip-maps) */ |
| } /* for (all texture layers) */ |
| |
| /* Release the reference color data buffer */ |
| delete[] reference_color_data; |
| reference_color_data = DE_NULL; |
| |
| /* All done */ |
| return result; |
| } |
| |
| /** Returns a different vec4 every time the function is called. Each component |
| * is assigned a normalized value within <0, 1> range. |
| * |
| * @return As per description. |
| **/ |
| tcu::Vec4 TextureViewTestViewSampling::getRandomReferenceColor() |
| { |
| static unsigned int seed = 195; |
| tcu::Vec4 result; |
| |
| result = tcu::Vec4(float((seed) % 255) / 255.0f, float((seed << 3) % 255) / 255.0f, |
| float((seed << 4) % 255) / 255.0f, float((seed << 5) % 255) / 255.0f); |
| |
| seed += 17; |
| |
| return result; |
| } |
| |
| /** Every test iteration is assigned a different set of so-called reference colors. |
| * Depending on the texture target, each reference color corresponds to an unique color |
| * used to build different layers/faces/mip-maps or even samples of tose. |
| * |
| * Once the reference color storage is initialized, this function can be used to retrieve |
| * details of a color allocated a specific sample of a layer/face mip-map. |
| * |
| * This function will cause an assertion failure if an invalid layer/face/mipmap/sample is |
| * requested, as well as if the reference color storage is not initialized at the time of the call. |
| * |
| * @param n_layer Layer index to use for the query. A value of 0 should be used for non-arrayed |
| * texture targets. |
| * @param n_face Face index to use for the query. A value of 0 should be used for non-CM texture |
| * targets. Otherwise: |
| * * 0 corresponds to +X; |
| * * 1 corresponds to -X; |
| * * 2 corresponds to +Y; |
| * * 3 corresponds to -Y; |
| * * 4 corresponds to +Z; |
| * * 5 corresponds to -Z. |
| * @param n_mipmap Mip-map index to use for the query. A value of 0 should be used for non-mipmapped |
| * texture targets. |
| * @param n_sample Sample index to use for the query. A value of 0 should be used for single-sampled |
| * texture targets. |
| * |
| * @return Requested color data. |
| **/ |
| tcu::Vec4 TextureViewTestViewSampling::getReferenceColor(unsigned int n_layer, unsigned int n_face, |
| unsigned int n_mipmap, unsigned int n_sample) |
| { |
| tcu::Vec4 result; |
| |
| DE_ASSERT(m_reference_color_storage != DE_NULL); |
| if (m_reference_color_storage != DE_NULL) |
| { |
| bool is_parent_texture_cm_cma = (m_iteration_parent_texture_target == GL_TEXTURE_CUBE_MAP || |
| m_iteration_parent_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| bool is_view_texture_cm_cma = (m_iteration_view_texture_target == GL_TEXTURE_CUBE_MAP || |
| m_iteration_view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| |
| if (is_view_texture_cm_cma && !is_parent_texture_cm_cma) |
| { |
| /* Parent texture is not using faces. Compute layer index, as |
| * if the texture was actually a CM or a CMA */ |
| unsigned int temp = n_layer * 6 /* layer-faces per layer */ + n_face; |
| |
| n_layer = temp; |
| n_face = 0; |
| } |
| else if (!is_view_texture_cm_cma && is_parent_texture_cm_cma) |
| { |
| /* The other way around - assume the texture is a CM or CMA */ |
| n_face = n_layer % 6; /* faces per cube-map layer */ |
| n_layer = n_layer / 6; /* faces per cube-map layer */ |
| } |
| |
| DE_ASSERT(n_face < m_reference_color_storage->n_faces); |
| DE_ASSERT(n_layer < m_reference_color_storage->n_layers); |
| DE_ASSERT(n_mipmap < m_reference_color_storage->n_mipmaps); |
| DE_ASSERT(n_sample < m_reference_color_storage->n_samples); |
| |
| /* Hierarchy is: |
| * |
| * layers -> faces -> mipmaps -> samples */ |
| const unsigned int index = |
| n_layer * (m_reference_color_storage->n_faces * m_reference_color_storage->n_mipmaps * |
| m_reference_color_storage->n_samples) + |
| n_face * (m_reference_color_storage->n_mipmaps * m_reference_color_storage->n_samples) + |
| n_mipmap * (m_reference_color_storage->n_samples) + n_sample; |
| |
| result = m_reference_color_storage->data[index]; |
| } |
| |
| return result; |
| } |
| |
| /* Retrieve max conformant sample count when GL_NV_internalformat_sample_query is supported */ |
| glw::GLint TextureViewTestViewSampling::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat) |
| { |
| (void)internalFormat; |
| glw::GLint max_conformant_samples = 0; |
| |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Return the max conformant sample count if extension is supported */ |
| if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query")) |
| { |
| glw::GLint gl_sample_counts = 0; |
| gl.getInternalformativ(target, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname"); |
| |
| /* Check and return the first conformant sample count */ |
| glw::GLint* gl_supported_samples = new glw::GLint[gl_sample_counts]; |
| if (gl_supported_samples) |
| { |
| gl.getInternalformativ(target, GL_RGBA8, GL_SAMPLES, gl_sample_counts, gl_supported_samples); |
| |
| for (glw::GLint i = 0; i < gl_sample_counts; i++) |
| { |
| glw::GLint isConformant = 0; |
| gl.getInternalformatSampleivNV(target, GL_RGBA8, gl_supported_samples[i], GL_CONFORMANT_NV, 1, |
| &isConformant); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed"); |
| |
| if (isConformant && gl_supported_samples[i] > max_conformant_samples) |
| { |
| max_conformant_samples = gl_supported_samples[i]; |
| } |
| } |
| delete[] gl_supported_samples; |
| } |
| } |
| else |
| { |
| /* Otherwise return GL_MAX_COLOR_TEXTURE_SAMPLES */ |
| gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &max_conformant_samples); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_COLOR_TEXTURE_SAMPLES pname."); |
| } |
| |
| return max_conformant_samples; |
| } |
| |
| /** Initializes iteration-specific program object used to sample the texture data. */ |
| void TextureViewTestViewSampling::initIterationSpecificProgramObject() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Release shader/program objects that may have been initialized in previous |
| * iterations. |
| */ |
| deinitIterationSpecificProgramAndShaderObjects(); |
| |
| /* Create program and shader objects */ |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); |
| m_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER); |
| m_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); |
| |
| m_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed."); |
| |
| /* Prepare token replacement strings */ |
| std::stringstream n_samples_sstream; |
| std::string sampler_declarations_string; |
| std::string sample_fetch_string; |
| std::string sample_fetch_fs_string; |
| std::size_t token_location = std::string::npos; |
| const char* token_n_samples = "N_SAMPLES"; |
| const char* token_sampler_declarations = "SAMPLER_DECLARATIONS"; |
| const char* token_sample_fetch = "SAMPLE_FETCH"; |
| |
| n_samples_sstream << m_iteration_parent_texture_n_samples; |
| |
| switch (m_iteration_view_texture_target) |
| { |
| case GL_TEXTURE_1D: |
| { |
| sampler_declarations_string = "uniform sampler1D texture;"; |
| sample_fetch_string = "vec4 current_sample = textureLod(texture, 0.5, lod);\n"; |
| sample_fetch_fs_string = "vec4 current_sample = textureLod(texture, gs_fs_uv.x, lod);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_1D_ARRAY: |
| { |
| sampler_declarations_string = "uniform sampler1DArray texture;\n" |
| "uniform float z_float;\n"; |
| |
| sample_fetch_string = "vec4 current_sample = textureLod(texture, vec2(0.5, z_float), lod);\n"; |
| sample_fetch_fs_string = "vec4 current_sample = textureLod(texture, vec2(gs_fs_uv.x, z_float), lod);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D: |
| { |
| sampler_declarations_string = "uniform sampler2D texture;"; |
| sample_fetch_string = "vec4 current_sample = textureLod(texture, vec2(0.5), lod);\n"; |
| sample_fetch_fs_string = "vec4 current_sample = textureLod(texture, gs_fs_uv, lod);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_ARRAY: |
| { |
| sampler_declarations_string = "uniform float z_float;\n" |
| "uniform sampler2DArray texture;"; |
| |
| sample_fetch_string = "vec4 current_sample = textureLod(texture, vec3(vec2(0.5), z_float), lod);\n"; |
| sample_fetch_fs_string = "vec4 current_sample = textureLod(texture, vec3(gs_fs_uv, z_float), lod);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| sampler_declarations_string = "uniform sampler2DMS texture;"; |
| sample_fetch_string = "ivec2 texture_size = textureSize(texture);\n" |
| "vec4 current_sample = texelFetch (texture,\n" |
| " ivec2(texture_size.xy / ivec2(2)),\n" |
| " n_sample);\n"; |
| |
| sample_fetch_fs_string = "ivec2 texture_size = textureSize(texture);\n" |
| "vec4 current_sample = texelFetch (texture,\n" |
| " ivec2(gs_fs_uv * vec2(texture_size)),\n" |
| " n_sample);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| sampler_declarations_string = "uniform sampler2DMSArray texture;" |
| "uniform int z_int;\n"; |
| |
| sample_fetch_string = "ivec3 texture_size = textureSize(texture);\n" |
| "vec4 current_sample = texelFetch (texture,\n" |
| " ivec3(texture_size.xy / ivec2(2), z_int),\n" |
| " n_sample);\n"; |
| |
| sample_fetch_fs_string = |
| "ivec3 texture_size = textureSize(texture);\n" |
| "vec4 current_sample = texelFetch (texture,\n" |
| " ivec3(ivec2(gs_fs_uv * vec2(texture_size).xy), z_int),\n" |
| " n_sample);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_3D: |
| { |
| sampler_declarations_string = "uniform sampler3D texture;" |
| "uniform float z_float;"; |
| |
| sample_fetch_string = "vec4 current_sample = textureLod(texture, vec3(vec2(0.5), z_float), lod);\n"; |
| sample_fetch_fs_string = "vec4 current_sample = textureLod(texture, vec3(gs_fs_uv, z_float), lod);\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP: |
| { |
| sampler_declarations_string = "uniform samplerCube texture;\n" |
| "uniform int n_face;"; |
| |
| sample_fetch_string = "vec4 current_sample;\n" |
| "\n" |
| "switch (n_face)\n" |
| "{\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_X |
| " case 0: current_sample = textureLod(texture, vec3( 1, 0, 0), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_X |
| " case 1: current_sample = textureLod(texture, vec3(-1, 0, 0), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Y |
| " case 2: current_sample = textureLod(texture, vec3( 0, 1, 0), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y |
| " case 3: current_sample = textureLod(texture, vec3( 0, -1, 0), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Z |
| " case 4: current_sample = textureLod(texture, vec3( 0, 0, 1), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
| " case 5: current_sample = textureLod(texture, vec3( 0, 0, -1), lod); break;\n" |
| "}\n"; |
| |
| sample_fetch_fs_string = |
| "vec4 current_sample;\n" |
| "\n" |
| "switch (n_face)\n" |
| "{\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_X |
| " case 0: current_sample = textureLod(texture, normalize(vec3( 1, gs_fs_uv.xy)), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_X |
| " case 1: current_sample = textureLod(texture, normalize(vec3(-1, gs_fs_uv.xy)), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Y |
| " case 2: current_sample = textureLod(texture, normalize(vec3( gs_fs_uv.x, 1, gs_fs_uv.y)), lod); " |
| "break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y |
| " case 3: current_sample = textureLod(texture, normalize(vec3( gs_fs_uv.x, -1, gs_fs_uv.y)), lod); " |
| "break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Z |
| " case 4: current_sample = textureLod(texture, normalize(vec3( gs_fs_uv.xy, 1)), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
| " case 5: current_sample = textureLod(texture, normalize(vec3( gs_fs_uv.xy, -1)), lod); break;\n" |
| "}\n"; |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| sampler_declarations_string = "uniform samplerCubeArray texture;\n" |
| "uniform int n_face;\n" |
| "uniform float z_float;\n"; |
| |
| sample_fetch_string = |
| "vec4 current_sample;\n" |
| "\n" |
| "switch (n_face)\n" |
| "{\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_X |
| " case 0: current_sample = textureLod(texture, vec4( 1, 0, 0, z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_X |
| " case 1: current_sample = textureLod(texture, vec4(-1, 0, 0, z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Y |
| " case 2: current_sample = textureLod(texture, vec4( 0, 1, 0, z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y |
| " case 3: current_sample = textureLod(texture, vec4( 0, -1, 0, z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Z |
| " case 4: current_sample = textureLod(texture, vec4( 0, 0, 1, z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
| " case 5: current_sample = textureLod(texture, vec4( 0, 0, -1, z_float), lod); break;\n" |
| "}\n"; |
| |
| sample_fetch_fs_string = "vec4 current_sample;\n" |
| "\n" |
| "switch (n_face)\n" |
| "{\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_X |
| " case 0: current_sample = textureLod(texture, vec4(normalize(vec3( 1, " |
| "gs_fs_uv.xy)), z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_X |
| " case 1: current_sample = textureLod(texture, vec4(normalize(vec3(-1, " |
| "gs_fs_uv.xy)), z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Y |
| " case 2: current_sample = textureLod(texture, vec4(normalize(vec3( gs_fs_uv.x, 1, " |
| " gs_fs_uv.y)), z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y |
| " case 3: current_sample = textureLod(texture, vec4(normalize(vec3( gs_fs_uv.x, " |
| "-1, gs_fs_uv.y)), z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_POSITIVE_Z |
| " case 4: current_sample = textureLod(texture, vec4(normalize(vec3( gs_fs_uv.xy, " |
| "1)), z_float), lod); break;\n" |
| // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
| " case 5: current_sample = textureLod(texture, vec4(normalize(vec3( gs_fs_uv.xy, " |
| "-1)), z_float), lod); break;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_RECTANGLE: |
| { |
| sampler_declarations_string = "uniform sampler2DRect texture;"; |
| sample_fetch_string = "ivec2 texture_size = textureSize(texture);\n" |
| "vec4 current_sample = texelFetch (texture, texture_size / ivec2(2));\n"; |
| |
| sample_fetch_fs_string = |
| "ivec2 texture_size = textureSize(texture);\n" |
| "vec4 current_sample = texelFetch (texture, ivec2(gs_fs_uv.xy * vec2(texture_size)));\n"; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture target"); |
| } |
| } /* switch (m_iteration_view_texture_target) */ |
| |
| /* Set vertex shader's body */ |
| const char* vs_body = "#version 400\n" |
| "\n" |
| "uniform float lod;\n" |
| "uniform vec4 reference_colors[N_SAMPLES];\n" |
| "SAMPLER_DECLARATIONS\n" |
| "\n" |
| "out int vs_tc_vs_sampling_result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float epsilon = 1.0 / 255.0;\n" |
| "\n" |
| " vs_tc_vs_sampling_result = 1;\n" |
| "\n" |
| " for (int n_sample = 0; n_sample < N_SAMPLES; ++n_sample)\n" |
| " {\n" |
| " SAMPLE_FETCH;\n" |
| "\n" |
| " if (abs(current_sample.x - reference_colors[n_sample].x) > epsilon ||\n" |
| " abs(current_sample.y - reference_colors[n_sample].y) > epsilon ||\n" |
| " abs(current_sample.z - reference_colors[n_sample].z) > epsilon ||\n" |
| " abs(current_sample.w - reference_colors[n_sample].w) > epsilon)\n" |
| " {\n" |
| " vs_tc_vs_sampling_result = int(current_sample.x * 256.0);\n" |
| "\n" |
| " break;\n" |
| " }\n" |
| " }\n" |
| "\n" |
| " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| std::string vs_string = vs_body; |
| |
| while ((token_location = vs_string.find(token_n_samples)) != std::string::npos) |
| { |
| vs_string.replace(token_location, strlen(token_n_samples), n_samples_sstream.str()); |
| } |
| |
| while ((token_location = vs_string.find(token_sampler_declarations)) != std::string::npos) |
| { |
| vs_string.replace(token_location, strlen(token_sampler_declarations), sampler_declarations_string); |
| } |
| |
| while ((token_location = vs_string.find(token_sample_fetch)) != std::string::npos) |
| { |
| vs_string.replace(token_location, strlen(token_sample_fetch), sample_fetch_string); |
| } |
| |
| /* Set tessellation control shader's body */ |
| const char* tc_body = "#version 400\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "uniform float lod;\n" |
| "uniform vec4 reference_colors[N_SAMPLES];\n" |
| "SAMPLER_DECLARATIONS\n" |
| "\n" |
| "in int vs_tc_vs_sampling_result[];\n" |
| "out int tc_te_vs_sampling_result[];\n" |
| "out int tc_te_tc_sampling_result[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float epsilon = 1.0 / 255.0;\n" |
| "\n" |
| " tc_te_vs_sampling_result[gl_InvocationID] = vs_tc_vs_sampling_result[gl_InvocationID];\n" |
| " tc_te_tc_sampling_result[gl_InvocationID] = 1;\n" |
| "\n" |
| " for (int n_sample = 0; n_sample < N_SAMPLES; ++n_sample)\n" |
| " {\n" |
| " SAMPLE_FETCH\n" |
| "\n" |
| " if (abs(current_sample.x - reference_colors[n_sample].x) > epsilon ||\n" |
| " abs(current_sample.y - reference_colors[n_sample].y) > epsilon ||\n" |
| " abs(current_sample.z - reference_colors[n_sample].z) > epsilon ||\n" |
| " abs(current_sample.w - reference_colors[n_sample].w) > epsilon)\n" |
| " {\n" |
| " tc_te_tc_sampling_result[gl_InvocationID] = 0;\n" |
| "\n" |
| " break;\n" |
| " }\n" |
| " }\n" |
| "\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| "}\n"; |
| |
| std::string tc_string = tc_body; |
| |
| while ((token_location = tc_string.find(token_n_samples)) != std::string::npos) |
| { |
| tc_string.replace(token_location, strlen(token_n_samples), n_samples_sstream.str()); |
| } |
| |
| while ((token_location = tc_string.find(token_sampler_declarations)) != std::string::npos) |
| { |
| tc_string.replace(token_location, strlen(token_sampler_declarations), sampler_declarations_string); |
| } |
| |
| while ((token_location = tc_string.find(token_sample_fetch)) != std::string::npos) |
| { |
| tc_string.replace(token_location, strlen(token_sample_fetch), sample_fetch_string); |
| } |
| |
| /* Set tessellation evaluation shader's body */ |
| const char* te_body = "#version 400\n" |
| "\n" |
| "layout(quads) in;\n" |
| "\n" |
| "in int tc_te_vs_sampling_result[];\n" |
| "in int tc_te_tc_sampling_result[];\n" |
| "out int te_gs_vs_sampling_result;\n" |
| "out int te_gs_tc_sampling_result;\n" |
| "out int te_gs_te_sampling_result;\n" |
| "out vec2 te_gs_uv;\n" |
| "\n" |
| "uniform float lod;\n" |
| "uniform vec4 reference_colors[N_SAMPLES];\n" |
| "SAMPLER_DECLARATIONS\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " te_gs_vs_sampling_result = tc_te_vs_sampling_result[0];\n" |
| " te_gs_tc_sampling_result = tc_te_tc_sampling_result[0];\n" |
| " te_gs_te_sampling_result = 1;\n" |
| "\n" |
| /* gl_TessCoord spans from 0 to 1 for XY. To generate a screen-space quad, |
| * we need to project these components to <-1, 1>. */ |
| " gl_Position.xy = gl_TessCoord.xy * 2.0 - 1.0;\n" |
| " gl_Position.zw = vec2(0, 1);\n" |
| " te_gs_uv = vec2(gl_TessCoord.x, 1.0 - gl_TessCoord.y);\n" |
| "\n" |
| "\n" |
| " const float epsilon = 1.0 / 255.0;\n" |
| "\n" |
| " for (int n_sample = 0; n_sample < N_SAMPLES; ++n_sample)\n" |
| " {\n" |
| " SAMPLE_FETCH\n" |
| "\n" |
| " if (abs(current_sample.x - reference_colors[n_sample].x) > epsilon ||\n" |
| " abs(current_sample.y - reference_colors[n_sample].y) > epsilon ||\n" |
| " abs(current_sample.z - reference_colors[n_sample].z) > epsilon ||\n" |
| " abs(current_sample.w - reference_colors[n_sample].w) > epsilon)\n" |
| " {\n" |
| " te_gs_te_sampling_result = 0;\n" |
| "\n" |
| " break;\n" |
| " }\n" |
| " }\n" |
| "\n" |
| "}\n"; |
| |
| std::string te_string = te_body; |
| |
| while ((token_location = te_string.find(token_n_samples)) != std::string::npos) |
| { |
| te_string.replace(token_location, strlen(token_n_samples), n_samples_sstream.str()); |
| } |
| |
| while ((token_location = te_string.find(token_sampler_declarations)) != std::string::npos) |
| { |
| te_string.replace(token_location, strlen(token_sampler_declarations), sampler_declarations_string); |
| } |
| |
| while ((token_location = te_string.find(token_sample_fetch)) != std::string::npos) |
| { |
| te_string.replace(token_location, strlen(token_sample_fetch), sample_fetch_string); |
| } |
| |
| /* Set geometry shader's body */ |
| const char* gs_body = "#version 400\n" |
| "\n" |
| "layout (triangles) in;\n" |
| "layout (triangle_strip, max_vertices = 3) out;\n" |
| "\n" |
| "in int te_gs_vs_sampling_result[];\n" |
| "in int te_gs_tc_sampling_result[];\n" |
| "in int te_gs_te_sampling_result[];\n" |
| "in vec2 te_gs_uv [];\n" |
| "out int gs_fs_vs_sampling_result;\n" |
| "out int gs_fs_tc_sampling_result;\n" |
| "out int gs_fs_te_sampling_result;\n" |
| "out int gs_fs_gs_sampling_result;\n" |
| "out vec2 gs_fs_uv;\n" |
| "\n" |
| "uniform float lod;\n" |
| "uniform vec4 reference_colors[N_SAMPLES];\n" |
| "SAMPLER_DECLARATIONS\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float epsilon = 1.0 / 255.0;\n" |
| " int gs_sampling_result = 1;\n" |
| " int tc_sampling_result = te_gs_tc_sampling_result[0] & " |
| "te_gs_tc_sampling_result[1] & te_gs_tc_sampling_result[2];\n" |
| " int te_sampling_result = te_gs_te_sampling_result[0] & " |
| "te_gs_te_sampling_result[1] & te_gs_te_sampling_result[2];\n" |
| " int vs_sampling_result = te_gs_vs_sampling_result[0] & " |
| "te_gs_vs_sampling_result[1] & te_gs_vs_sampling_result[2];\n" |
| "\n" |
| " for (int n_sample = 0; n_sample < N_SAMPLES; ++n_sample)\n" |
| " {\n" |
| " SAMPLE_FETCH;\n" |
| "\n" |
| " if (abs(current_sample.x - reference_colors[n_sample].x) > epsilon ||\n" |
| " abs(current_sample.y - reference_colors[n_sample].y) > epsilon ||\n" |
| " abs(current_sample.z - reference_colors[n_sample].z) > epsilon ||\n" |
| " abs(current_sample.w - reference_colors[n_sample].w) > epsilon)\n" |
| " {\n" |
| " gs_sampling_result = 0;\n" |
| "\n" |
| " break;\n" |
| " }\n" |
| " }\n" |
| "\n" |
| " gl_Position = gl_in[0].gl_Position;\n" |
| " gs_fs_uv = te_gs_uv[0];\n" |
| " gs_fs_gs_sampling_result = gs_sampling_result;\n" |
| " gs_fs_tc_sampling_result = tc_sampling_result;\n" |
| " gs_fs_te_sampling_result = te_sampling_result;\n" |
| " gs_fs_vs_sampling_result = vs_sampling_result;\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = gl_in[1].gl_Position;\n" |
| " gs_fs_uv = te_gs_uv[1];\n" |
| " gs_fs_gs_sampling_result = gs_sampling_result;\n" |
| " gs_fs_tc_sampling_result = tc_sampling_result;\n" |
| " gs_fs_te_sampling_result = te_sampling_result;\n" |
| " gs_fs_vs_sampling_result = vs_sampling_result;\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = gl_in[2].gl_Position;\n" |
| " gs_fs_uv = te_gs_uv[2];\n" |
| " gs_fs_gs_sampling_result = gs_sampling_result;\n" |
| " gs_fs_tc_sampling_result = tc_sampling_result;\n" |
| " gs_fs_te_sampling_result = te_sampling_result;\n" |
| " gs_fs_vs_sampling_result = vs_sampling_result;\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| "}\n"; |
| |
| std::string gs_string = gs_body; |
| |
| while ((token_location = gs_string.find(token_n_samples)) != std::string::npos) |
| { |
| gs_string.replace(token_location, strlen(token_n_samples), n_samples_sstream.str()); |
| } |
| |
| while ((token_location = gs_string.find(token_sampler_declarations)) != std::string::npos) |
| { |
| gs_string.replace(token_location, strlen(token_sampler_declarations), sampler_declarations_string); |
| } |
| |
| while ((token_location = gs_string.find(token_sample_fetch)) != std::string::npos) |
| { |
| gs_string.replace(token_location, strlen(token_sample_fetch), sample_fetch_string); |
| } |
| |
| /* Set fragment shader's body */ |
| const char* fs_body = "#version 400\n" |
| "\n" |
| "in vec2 gs_fs_uv;\n" |
| "\n" |
| "uniform float lod;\n" |
| "uniform vec4 reference_colors[N_SAMPLES];\n" |
| "SAMPLER_DECLARATIONS\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float epsilon = 1.0 / 255.0;\n" |
| "\n" |
| " result = vec4(1.0);\n" |
| "\n" |
| " for (int n_sample = 0; n_sample < N_SAMPLES; ++n_sample)\n" |
| " {\n" |
| " SAMPLE_FETCH\n" |
| "\n" |
| " if (abs(current_sample.x - reference_colors[n_sample].x) > epsilon ||\n" |
| " abs(current_sample.y - reference_colors[n_sample].y) > epsilon ||\n" |
| " abs(current_sample.z - reference_colors[n_sample].z) > epsilon ||\n" |
| " abs(current_sample.w - reference_colors[n_sample].w) > epsilon)\n" |
| " {\n" |
| " result = vec4(0.0);\n" |
| "\n" |
| " break;\n" |
| " }\n" |
| " }\n" |
| "}\n"; |
| |
| std::string fs_string = fs_body; |
| |
| while ((token_location = fs_string.find(token_n_samples)) != std::string::npos) |
| { |
| fs_string.replace(token_location, strlen(token_n_samples), n_samples_sstream.str()); |
| } |
| |
| while ((token_location = fs_string.find(token_sampler_declarations)) != std::string::npos) |
| { |
| fs_string.replace(token_location, strlen(token_sampler_declarations), sampler_declarations_string); |
| } |
| |
| while ((token_location = fs_string.find(token_sample_fetch)) != std::string::npos) |
| { |
| fs_string.replace(token_location, strlen(token_sample_fetch), sample_fetch_fs_string); |
| } |
| |
| /* Configure shader bodies */ |
| const char* fs_body_raw_ptr = fs_string.c_str(); |
| const char* gs_body_raw_ptr = gs_string.c_str(); |
| const char* tc_body_raw_ptr = tc_string.c_str(); |
| const char* te_body_raw_ptr = te_string.c_str(); |
| const char* vs_body_raw_ptr = vs_string.c_str(); |
| |
| gl.shaderSource(m_fs_id, 1 /* count */, &fs_body_raw_ptr, NULL /* length */); |
| gl.shaderSource(m_gs_id, 1 /* count */, &gs_body_raw_ptr, NULL /* length */); |
| gl.shaderSource(m_tc_id, 1 /* count */, &tc_body_raw_ptr, NULL /* length */); |
| gl.shaderSource(m_te_id, 1 /* count */, &te_body_raw_ptr, NULL /* length */); |
| gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed."); |
| |
| /* Compile the shaders */ |
| const glw::GLuint so_ids[] = { m_fs_id, m_gs_id, m_tc_id, m_te_id, m_vs_id }; |
| const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]); |
| |
| const glw::GLchar* shader_sources[] = { fs_body_raw_ptr, gs_body_raw_ptr, tc_body_raw_ptr, te_body_raw_ptr, |
| vs_body_raw_ptr }; |
| |
| for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id) |
| { |
| glw::GLint compile_status = GL_FALSE; |
| glw::GLint so_id = so_ids[n_so_id]; |
| |
| gl.compileShader(so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| char temp[1024]; |
| |
| gl.getShaderInfoLog(so_id, 1024, NULL, temp); |
| |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation error log:\n" |
| << temp << "\nShader source:\n" |
| << shader_sources[n_so_id] << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Shader compilation failed"); |
| } |
| |
| /* Attach the shaders to the program object */ |
| gl.attachShader(m_po_id, so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed"); |
| } /* for (all shader objects) */ |
| |
| /* Set up XFB */ |
| const char* varying_names[] = { "gs_fs_vs_sampling_result", "gs_fs_tc_sampling_result", "gs_fs_te_sampling_result", |
| "gs_fs_gs_sampling_result" }; |
| const unsigned int n_varying_names = sizeof(varying_names) / sizeof(varying_names[0]); |
| |
| gl.transformFeedbackVaryings(m_po_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); |
| |
| /* Link the program object */ |
| glw::GLint link_status = GL_FALSE; |
| |
| gl.linkProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status != GL_TRUE) |
| { |
| TCU_FAIL("Program linking failed."); |
| } |
| |
| /* Retrieve uniform locations. Depending on the iteration, a number of those will be |
| * inactive. |
| */ |
| m_po_lod_location = gl.getUniformLocation(m_po_id, "lod"); |
| m_po_n_face_location = gl.getUniformLocation(m_po_id, "n_face"); |
| m_po_reference_colors_location = gl.getUniformLocation(m_po_id, "reference_colors"); |
| m_po_texture_location = gl.getUniformLocation(m_po_id, "texture"); |
| m_po_z_float_location = gl.getUniformLocation(m_po_id, "z_float"); |
| m_po_z_int_location = gl.getUniformLocation(m_po_id, "z_int"); |
| |
| if (m_po_reference_colors_location == -1) |
| { |
| TCU_FAIL("reference_colors is considered an inactive uniform which is invalid."); |
| } |
| } |
| |
| /** Initializes contents of a texture, from which the view texture will be created. **/ |
| void TextureViewTestViewSampling::initParentTextureContents() |
| { |
| static const glw::GLenum cm_texture_targets[] = { |
| /* NOTE: This order must match the order used for sampling CM/CMA texture targets. */ |
| GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
| }; |
| static const unsigned int n_cm_texture_targets = sizeof(cm_texture_targets) / sizeof(cm_texture_targets[0]); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Bind the parent texture */ |
| gl.bindTexture(m_iteration_parent_texture_target, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* If we're dealing with a single-sampled texture target, then we can clear the |
| * contents of each layer/face/slice using FBO. This will unfortunately not work |
| * for arrayed textures, layers or layer-faces of which cannot be attached to a draw |
| * framebuffer. |
| * If we need to update contents of a multisampled, potentially arrayed texture, |
| * we'll need to use the filler program. |
| **/ |
| bool is_arrayed_texture_target = (m_iteration_parent_texture_target == GL_TEXTURE_1D_ARRAY || |
| m_iteration_parent_texture_target == GL_TEXTURE_2D_ARRAY || |
| m_iteration_parent_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| bool is_multisampled_texture_target = (m_iteration_parent_texture_target == GL_TEXTURE_2D_MULTISAMPLE || |
| m_iteration_parent_texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); |
| |
| if (!is_arrayed_texture_target && !is_multisampled_texture_target) |
| { |
| /* Good, no need to work with samples! */ |
| DE_ASSERT(m_iteration_parent_texture_depth >= 1); |
| DE_ASSERT(m_iteration_parent_texture_n_levels >= 1); |
| |
| /* Cube-map texture target cannot be directly used for a glFramebufferTexture2D() call. Instead, |
| * we need to split it into 6 cube-map texture targets. */ |
| unsigned int n_texture_targets = 1; |
| glw::GLenum texture_targets[n_cm_texture_targets] = { |
| m_iteration_parent_texture_target, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, |
| }; |
| |
| if (m_iteration_parent_texture_target == GL_TEXTURE_CUBE_MAP) |
| { |
| DE_STATIC_ASSERT(sizeof(texture_targets) == sizeof(cm_texture_targets)); |
| memcpy(texture_targets, cm_texture_targets, sizeof(cm_texture_targets)); |
| |
| n_texture_targets = n_cm_texture_targets; |
| } |
| |
| resetReferenceColorStorage(m_iteration_parent_texture_depth, /* n_layers */ |
| n_texture_targets, /* n_faces */ |
| m_iteration_parent_texture_n_levels, /* n_mipmaps */ |
| 1); /* n_samples */ |
| |
| /* Iterate through all texture targets we need to update */ |
| for (unsigned int n_texture_target = 0; n_texture_target < n_texture_targets; ++n_texture_target) |
| { |
| const glw::GLenum texture_target = texture_targets[n_texture_target]; |
| |
| /* Iterate through all layers of the texture. */ |
| for (unsigned int n_layer = 0; n_layer < m_iteration_parent_texture_depth; ++n_layer) |
| { |
| /* ..and mip-maps, too. */ |
| const unsigned int n_mipmaps_for_layer = (texture_target == GL_TEXTURE_3D) ? |
| (m_iteration_parent_texture_n_levels - n_layer) : |
| (m_iteration_parent_texture_n_levels); |
| |
| for (unsigned int n_mipmap = 0; n_mipmap < n_mipmaps_for_layer; ++n_mipmap) |
| { |
| /* Use appropriate glFramebufferTexture*() API, depending on the texture target of the |
| * parent texture. |
| */ |
| switch (texture_target) |
| { |
| case GL_TEXTURE_1D: |
| { |
| gl.framebufferTexture1D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_1D, m_to_id, |
| n_mipmap); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture1D() call failed."); |
| break; |
| } |
| |
| case GL_TEXTURE_2D: |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_X: |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: |
| case GL_TEXTURE_RECTANGLE: |
| { |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, m_to_id, |
| n_mipmap); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); |
| break; |
| } |
| |
| case GL_TEXTURE_3D: |
| { |
| gl.framebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, m_to_id, |
| n_mipmap, n_layer); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture3D() call failed."); |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture target"); |
| } |
| } /* switch (m_iteration_parent_texture_target) */ |
| |
| /* Each layer/mipmap needs to be assigned an unique vec4. */ |
| tcu::Vec4 reference_color = getRandomReferenceColor(); |
| |
| setReferenceColor(n_layer, n_texture_target, /* n_face */ |
| n_mipmap, 0, /* n_sample */ |
| reference_color); |
| |
| /* We should be OK to clear the mip-map at this point */ |
| gl.clearColor(reference_color.x(), reference_color.y(), reference_color.z(), reference_color.w()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed."); |
| |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed."); |
| } /* for (all mip-maps) */ |
| } /* for (all layers) */ |
| } /* for (all texture targets) */ |
| } /* if (!is_arrayed_texture_target && !is_multisampled_texture_target) */ |
| else |
| { |
| /* We need to handle an either multisampled or arrayed texture target or |
| * a combination of the two. |
| */ |
| DE_ASSERT(m_iteration_parent_texture_target == GL_TEXTURE_1D_ARRAY || |
| m_iteration_parent_texture_target == GL_TEXTURE_2D_ARRAY || |
| m_iteration_parent_texture_target == GL_TEXTURE_2D_MULTISAMPLE || |
| m_iteration_parent_texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || |
| m_iteration_parent_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| |
| DE_ASSERT(m_iteration_parent_texture_depth >= 1); |
| DE_ASSERT(m_iteration_parent_texture_n_levels >= 1); |
| |
| const unsigned int n_faces = |
| (m_iteration_parent_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY) ? 6 /* faces */ : 1; |
| |
| resetReferenceColorStorage(m_iteration_parent_texture_depth, /* n_layers */ |
| n_faces, m_iteration_parent_texture_n_levels, /* n_mipmaps */ |
| m_max_color_texture_samples_gl_value); /* n_samples */ |
| |
| /* Set up storage for reference colors the fragment shader should use |
| * when rendering to multisampled texture target */ |
| float* reference_colors = new float[4 /* rgba */ * m_max_color_texture_samples_gl_value]; |
| |
| /* Activate the filler program */ |
| gl.useProgram(m_per_sample_filler_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| /* Iterate through all layers of the texture. */ |
| for (unsigned int n_layer = 0; n_layer < m_iteration_parent_texture_depth; ++n_layer) |
| { |
| /* ..faces.. */ |
| for (unsigned int n_face = 0; n_face < n_faces; ++n_face) |
| { |
| /* ..and mip-maps, too. */ |
| for (unsigned int n_mipmap = 0; n_mipmap < m_iteration_parent_texture_n_levels; ++n_mipmap) |
| { |
| /* For all texture targets considered excl. GL_TEXTURE_2D_MULTISAMPLE, we need |
| * to use glFramebufferTextur() to bind all layers to the color atatchment. For |
| * 2DMS textures, we can use plain glFramebufferTexture2D(). |
| */ |
| if (m_iteration_parent_texture_target != GL_TEXTURE_2D_MULTISAMPLE) |
| { |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, n_mipmap); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTextureLayer() call failed."); |
| } |
| else |
| { |
| /* Sanity check */ |
| DE_ASSERT(m_iteration_parent_texture_depth == 1); |
| |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| m_iteration_parent_texture_target, m_to_id, n_mipmap); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); |
| } |
| |
| /* Generate reference colors for all samples */ |
| const unsigned int n_samples = |
| (is_multisampled_texture_target) ? m_max_color_texture_samples_gl_value : 1; |
| |
| for (unsigned int n_sample = 0; n_sample < n_samples; ++n_sample) |
| { |
| tcu::Vec4 reference_color = getRandomReferenceColor(); |
| |
| reference_colors[4 /* rgba */ * n_sample + 0] = reference_color.x(); |
| reference_colors[4 /* rgba */ * n_sample + 1] = reference_color.y(); |
| reference_colors[4 /* rgba */ * n_sample + 2] = reference_color.z(); |
| reference_colors[4 /* rgba */ * n_sample + 3] = reference_color.w(); |
| |
| setReferenceColor(n_layer, n_face, n_mipmap, n_sample, reference_color); |
| } /* for (all samples) */ |
| |
| /* Upload the reference sample colors */ |
| gl.uniform4fv(m_per_sample_filler_po_reference_colors_location, n_samples, reference_colors); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed."); |
| |
| /* Update the layer ID the program should render to */ |
| const unsigned int layer_id = n_face * 6 /* faces */ + n_layer; |
| |
| gl.uniform1i(m_per_sample_filler_po_layer_id_location, layer_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| |
| /* Draw the full-screen quad. Geometry shader will draw the quad for us, |
| * so all we need to do is to feed the rendering pipeline with a single |
| * point. |
| */ |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } /* for (all mip-maps) */ |
| } /* for (all faces) */ |
| } /* for (all layers) */ |
| |
| delete[] reference_colors; |
| } |
| } |
| |
| /** Initializes the 'per sample filler' program object, used to fill a multi-sample texture |
| * with colors varying on a per-sample basis. |
| */ |
| void TextureViewTestViewSampling::initPerSampleFillerProgramObject() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Sanity checks: GL_MAX_COLOR_TEXTURE_SAMPLES is not 0 */ |
| DE_ASSERT(m_max_color_texture_samples_gl_value != 0); |
| |
| /* Generate program and shader objects */ |
| m_per_sample_filler_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_per_sample_filler_gs_id = gl.createShader(GL_GEOMETRY_SHADER); |
| m_per_sample_filler_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); |
| |
| m_per_sample_filler_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); |
| |
| /* Configure fragment shader's body */ |
| static const char* fs_body = "#version 400\n" |
| "\n" |
| "uniform vec4 reference_colors[N_MAX_SAMPLES];\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = reference_colors[gl_SampleID];\n" |
| "}\n"; |
| std::string fs_body_string = fs_body; |
| const char* fs_body_string_raw_ptr = DE_NULL; |
| std::stringstream n_max_samples_sstream; |
| const char* n_max_samples_token = "N_MAX_SAMPLES"; |
| std::size_t token_location = std::string::npos; |
| |
| n_max_samples_sstream << m_max_color_texture_samples_gl_value; |
| |
| while ((token_location = fs_body_string.find(n_max_samples_token)) != std::string::npos) |
| { |
| fs_body_string.replace(token_location, strlen(n_max_samples_token), n_max_samples_sstream.str()); |
| } |
| |
| fs_body_string_raw_ptr = fs_body_string.c_str(); |
| |
| gl.shaderSource(m_per_sample_filler_fs_id, 1 /* count */, &fs_body_string_raw_ptr, DE_NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Configure geometry shader's body */ |
| static const char* gs_body = "#version 400\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "uniform int layer_id;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Layer = layer_id;\n" |
| " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = layer_id;\n" |
| " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = layer_id;\n" |
| " gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = layer_id;\n" |
| " gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n" |
| " EmitVertex();\n" |
| "\n" |
| " EndPrimitive();\n" |
| "\n" |
| "}\n"; |
| |
| gl.shaderSource(m_per_sample_filler_gs_id, 1 /* count */, &gs_body, DE_NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Configure vertex shader */ |
| static const char* vs_body = "#version 400\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| "}\n"; |
| |
| gl.shaderSource(m_per_sample_filler_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Attach the shaders to the program object */ |
| gl.attachShader(m_per_sample_filler_po_id, m_per_sample_filler_fs_id); |
| gl.attachShader(m_per_sample_filler_po_id, m_per_sample_filler_gs_id); |
| gl.attachShader(m_per_sample_filler_po_id, m_per_sample_filler_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); |
| |
| /* Compile the shaders */ |
| const glw::GLuint so_ids[] = { m_per_sample_filler_fs_id, m_per_sample_filler_gs_id, m_per_sample_filler_vs_id }; |
| const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]); |
| |
| for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id) |
| { |
| glw::GLint compile_status = GL_FALSE; |
| glw::GLuint so_id = so_ids[n_so_id]; |
| |
| gl.compileShader(so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiV() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| TCU_FAIL("Shader compilation failed."); |
| } |
| } /* for (all shader objects) */ |
| |
| /* Link the program object */ |
| glw::GLint link_status = GL_FALSE; |
| |
| gl.linkProgram(m_per_sample_filler_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| gl.getProgramiv(m_per_sample_filler_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status != GL_TRUE) |
| { |
| TCU_FAIL("Program linking failed."); |
| } |
| |
| /* Retrieve uniform locations */ |
| m_per_sample_filler_po_layer_id_location = gl.getUniformLocation(m_per_sample_filler_po_id, "layer_id"); |
| m_per_sample_filler_po_reference_colors_location = |
| gl.getUniformLocation(m_per_sample_filler_po_id, "reference_colors[0]"); |
| |
| if (m_per_sample_filler_po_layer_id_location == -1) |
| { |
| TCU_FAIL("layer_id uniform is considered inactive which is invalid"); |
| } |
| |
| if (m_per_sample_filler_po_reference_colors_location == -1) |
| { |
| TCU_FAIL("reference_colors uniform is considered inactive which is invalid"); |
| } |
| } |
| |
| /** Initializes GL objects needed to run the test (excluding iteration-specific objects) */ |
| void TextureViewTestViewSampling::initTest() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate and configure BO storage to hold result XFB data of a single |
| * draw call. |
| * |
| * Each draw call outputs 6 vertices. For each vertex, 4 ints will be XFBed out. */ |
| gl.genBuffers(1, &m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 6 /* draw calls */ * (4 * sizeof(int)), /* as per comment */ |
| DE_NULL, GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); |
| |
| /* Generate a FBO and bind it to both binding targets */ |
| gl.genFramebuffers(1, &m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed."); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); |
| |
| /* Generate and bind a VAO */ |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); |
| |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); |
| |
| /* Generate and configure a texture object we will use to verify view sampling works correctly |
| * from within a fragment shader. |
| */ |
| gl.genTextures(1, &m_result_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_result_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, m_reference_texture_width, m_reference_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| /* Determine implementation-specific GL_MAX_COLOR_TEXTURE_SAMPLES value */ |
| gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &m_max_color_texture_samples_gl_value); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_COLOR_TEXTURE_SAMPLES pname."); |
| |
| /* Modify pixel storage settings so that we don't rely on the default aligment setting. */ |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 1); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call(s) failed."); |
| |
| /* Modify GL_PATCH_VERTICES setting so that a single patch consists of only a single vertex |
| * (instead of the default 3) */ |
| gl.patchParameteri(GL_PATCH_VERTICES, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed."); |
| } |
| |
| /** Initializes and sets up a texture object storage, but does not fill it |
| * with actual content. Implements separate code paths for handling parent |
| * & view textures. |
| * |
| * @param is_view_texture true if a view texture should be initialized, |
| * false if te caller needs a parent texture. Note |
| * that a parent texture must be initialized prior |
| * to configuring a view texture. |
| * @param texture_target Texture target to use for the parent texture. |
| * @param view_texture_target Texture target to use for the view texture. |
| **/ |
| void TextureViewTestViewSampling::initTextureObject(bool is_view_texture, glw::GLenum texture_target, |
| glw::GLenum view_texture_target) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| unsigned int texture_depth = 0; |
| glw::GLuint* to_id_ptr = (is_view_texture) ? &m_view_to_id : &m_to_id; |
| |
| /* Sanity check: make sure GL_TEXTURE_BUFFER texture target is not requested. This |
| * would be against the test specification. |
| **/ |
| DE_ASSERT(texture_target != GL_TEXTURE_BUFFER); |
| DE_ASSERT(view_texture_target != GL_TEXTURE_BUFFER); |
| |
| /* If we're going to be creating a cube-map or cube-map array texture view in this iteration, |
| * make sure the parent or view texture's depth is valid */ |
| if (view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| texture_depth = 13; /* 1 + 2 * (6 faces) */ |
| } |
| else if (view_texture_target == GL_TEXTURE_CUBE_MAP) |
| { |
| texture_depth = 7; /* 1 + (6 faces) */ |
| } |
| else |
| { |
| texture_depth = m_reference_texture_depth; |
| } |
| |
| if (texture_target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| texture_depth = 6 /* faces */ * 3; |
| } |
| |
| /* Release the texture object, as we're using immutable texture objects and would |
| * prefer the resources not to leak. |
| */ |
| if (*to_id_ptr != 0) |
| { |
| gl.deleteTextures(1, to_id_ptr); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call failed."); |
| } |
| |
| /* Generate a new texture object */ |
| gl.genTextures(1, to_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); |
| |
| if (is_view_texture) |
| { |
| /* Determine values of arguments we'll pass to glTextureView() call */ |
| unsigned int minlayer = 0; |
| unsigned int minlevel = 0; |
| unsigned int numlayers = 0; |
| unsigned int numlevels = 2; |
| |
| const bool is_texture_arrayed_texture_target = |
| (texture_target == GL_TEXTURE_1D_ARRAY || texture_target == GL_TEXTURE_2D_ARRAY || |
| texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| const bool is_texture_cube_map_texture_target = (texture_target == GL_TEXTURE_CUBE_MAP); |
| const bool is_texture_multisample_texture_target = |
| (texture_target == GL_TEXTURE_2D_MULTISAMPLE || texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); |
| const bool is_texture_rectangle_texture_target = (texture_target == GL_TEXTURE_RECTANGLE); |
| const bool is_view_arrayed_texture_target = |
| (view_texture_target == GL_TEXTURE_1D_ARRAY || view_texture_target == GL_TEXTURE_2D_ARRAY || |
| view_texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || |
| view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| const bool is_view_cube_map_texture_target = (view_texture_target == GL_TEXTURE_CUBE_MAP); |
| const bool is_view_cube_map_array_texture_target = (view_texture_target == GL_TEXTURE_CUBE_MAP_ARRAY); |
| |
| if (is_texture_multisample_texture_target || is_texture_rectangle_texture_target) |
| { |
| minlevel = 0; |
| numlevels = 1; |
| } |
| else |
| { |
| minlevel = 1; |
| } |
| |
| if ((true == is_texture_arrayed_texture_target) || |
| ((false == is_texture_cube_map_texture_target) && (true == is_view_cube_map_texture_target)) || |
| ((false == is_texture_cube_map_texture_target) && (true == is_view_cube_map_array_texture_target))) |
| { |
| minlayer = 1; |
| } |
| else |
| { |
| minlayer = 0; |
| } |
| |
| if (!is_texture_cube_map_texture_target && is_view_cube_map_array_texture_target) |
| { |
| numlayers = 12; |
| } |
| else if (is_view_cube_map_texture_target || is_view_cube_map_array_texture_target) |
| { |
| numlayers = 6; |
| } |
| else if (is_view_arrayed_texture_target) |
| { |
| if (is_texture_arrayed_texture_target || is_texture_cube_map_texture_target) |
| { |
| numlayers = 2; |
| } |
| else |
| { |
| numlayers = 1; |
| } |
| } |
| else |
| { |
| numlayers = 1; |
| } |
| |
| /* Set up view texture */ |
| gl.textureView(*to_id_ptr, view_texture_target, m_to_id, GL_RGBA8, minlevel, numlevels, minlayer, numlayers); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed."); |
| |
| /* Store the argument values */ |
| m_iteration_view_texture_minlayer = minlayer; |
| m_iteration_view_texture_minlevel = minlevel; |
| m_iteration_view_texture_numlayers = numlayers; |
| m_iteration_view_texture_numlevels = numlevels; |
| m_iteration_view_texture_target = view_texture_target; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "Created a view for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(view_texture_target) << "] " |
| << "from a parent texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "using arguments: " |
| << "minlayer:[" << minlayer << "] " |
| << "minlevel:[" << minlevel << "] " |
| << "numlayers:[" << numlayers << "] " |
| << "numlevels:[" << numlevels << "]." << tcu::TestLog::EndMessage; |
| |
| gl.bindTexture(view_texture_target, *to_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| } /* if (is_view_texture) */ |
| else |
| { |
| /* Reset iteration-specific view settings */ |
| m_iteration_parent_texture_depth = 1; |
| m_iteration_parent_texture_height = 1; |
| m_iteration_parent_texture_n_levels = 1; |
| m_iteration_parent_texture_n_samples = 1; |
| m_iteration_parent_texture_width = 1; |
| |
| /* Initialize storage for the newly created texture object */ |
| gl.bindTexture(texture_target, *to_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Use max conformant sample count for multisample texture targets */ |
| if (texture_target == GL_TEXTURE_2D_MULTISAMPLE || texture_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) |
| { |
| m_max_color_texture_samples_gl_value = getMaxConformantSampleCount(texture_target, GL_RGBA8); |
| } |
| else |
| { |
| /* Use GL_MAX_COLOR_TEXTURE_SAMPLES value for other targets */ |
| gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &m_max_color_texture_samples_gl_value); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_COLOR_TEXTURE_SAMPLES pname."); |
| } |
| |
| switch (texture_target) |
| { |
| case GL_TEXTURE_1D: |
| { |
| gl.texStorage1D(texture_target, m_reference_texture_n_mipmaps, GL_RGBA8, m_reference_texture_width); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage1D() call failed."); |
| |
| m_iteration_parent_texture_n_levels = m_reference_texture_n_mipmaps; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "levels:[" << m_reference_texture_n_mipmaps << "] " |
| << "width:[" << m_reference_texture_width << "]." << tcu::TestLog::EndMessage; |
| break; |
| } |
| |
| case GL_TEXTURE_1D_ARRAY: |
| { |
| gl.texStorage2D(texture_target, m_reference_texture_n_mipmaps, GL_RGBA8, m_reference_texture_width, |
| texture_depth); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| m_iteration_parent_texture_depth = texture_depth; |
| m_iteration_parent_texture_n_levels = m_reference_texture_n_mipmaps; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "depth:[" << texture_depth << "] " |
| << "levels:[" << m_reference_texture_n_mipmaps << "] " |
| << "width:[" << m_reference_texture_width << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_CUBE_MAP: |
| case GL_TEXTURE_2D: |
| { |
| gl.texStorage2D(texture_target, m_reference_texture_n_mipmaps, GL_RGBA8, m_reference_texture_width, |
| m_reference_texture_height); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| m_iteration_parent_texture_height = m_reference_texture_height; |
| m_iteration_parent_texture_n_levels = m_reference_texture_n_mipmaps; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "levels:[" << m_reference_texture_n_mipmaps << "] " |
| << "width:[" << m_reference_texture_width << "] " |
| << "height:[" << m_reference_texture_height << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_RECTANGLE: |
| { |
| gl.texStorage2D(texture_target, 1, /* rectangle textures do not use mip-maps */ |
| GL_RGBA8, m_reference_texture_width, m_reference_texture_height); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| m_iteration_parent_texture_height = m_reference_texture_height; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "levels:1 " |
| << "width:[" << m_reference_texture_width << "] " |
| << "height:[" << m_reference_texture_height << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_ARRAY: |
| { |
| gl.texStorage3D(texture_target, m_reference_texture_n_mipmaps, GL_RGBA8, m_reference_texture_width, |
| m_reference_texture_height, texture_depth); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed."); |
| |
| m_iteration_parent_texture_depth = texture_depth; |
| m_iteration_parent_texture_height = m_reference_texture_height; |
| m_iteration_parent_texture_n_levels = m_reference_texture_n_mipmaps; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "depth:[" << texture_depth << "] " |
| << "levels:[" << m_reference_texture_n_mipmaps << "] " |
| << "width:[" << m_reference_texture_width << "] " |
| << "height:[" << m_reference_texture_height << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| gl.texStorage2DMultisample(texture_target, m_max_color_texture_samples_gl_value, GL_RGBA8, |
| m_reference_texture_width, m_reference_texture_height, |
| GL_TRUE); /* fixedsamplelocations */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2DMultisample() call failed."); |
| |
| m_iteration_parent_texture_height = m_reference_texture_height; |
| m_iteration_parent_texture_n_samples = m_max_color_texture_samples_gl_value; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "samples:[" << m_max_color_texture_samples_gl_value << "] " |
| << "width:[" << m_reference_texture_width << "] " |
| << "height:[" << m_reference_texture_height << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| gl.texStorage3DMultisample(texture_target, m_max_color_texture_samples_gl_value, GL_RGBA8, |
| m_reference_texture_width, m_reference_texture_height, texture_depth, |
| GL_TRUE); /* fixed sample locations */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3DMultisample() call failed."); |
| |
| m_iteration_parent_texture_depth = texture_depth; |
| m_iteration_parent_texture_height = m_reference_texture_height; |
| m_iteration_parent_texture_n_samples = m_max_color_texture_samples_gl_value; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "samples:[" << m_max_color_texture_samples_gl_value << "] " |
| << "width:[" << m_reference_texture_width << "] " |
| << "height:[" << m_reference_texture_height << "] " |
| << "depth:[" << texture_depth << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case GL_TEXTURE_3D: |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| gl.texStorage3D(texture_target, m_reference_texture_n_mipmaps, GL_RGBA8, m_reference_texture_width, |
| m_reference_texture_height, texture_depth); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage3D() call failed."); |
| |
| m_iteration_parent_texture_depth = texture_depth; |
| m_iteration_parent_texture_height = m_reference_texture_height; |
| m_iteration_parent_texture_n_levels = m_reference_texture_n_mipmaps; |
| m_iteration_parent_texture_width = m_reference_texture_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Created an immutable parent texture object for texture target " |
| << "[" << TextureViewUtilities::getTextureTargetString(texture_target) << "] " |
| << "of " |
| << "levels:[" << m_reference_texture_n_mipmaps << "] " |
| << "width:[" << m_reference_texture_width << "] " |
| << "height:[" << m_reference_texture_height << "] " |
| << "depth:[" << texture_depth << "]." << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture target."); |
| } |
| } /* switch (texture_target) */ |
| |
| m_iteration_parent_texture_target = texture_target; |
| } |
| |
| /* Configure texture filtering */ |
| if (texture_target != GL_TEXTURE_2D_MULTISAMPLE && texture_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY && |
| texture_target != GL_TEXTURE_RECTANGLE) |
| { |
| gl.texParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl.texParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call(s) failed."); |
| } |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestViewSampling::iterate() |
| { |
| bool has_failed = false; |
| |
| /* Make sure GL_ARB_texture_view is reported as supported before carrying on |
| * with actual execution */ |
| const std::vector<std::string>& extensions = m_context.getContextInfo().getExtensions(); |
| |
| if (std::find(extensions.begin(), extensions.end(), "GL_ARB_texture_view") == extensions.end()) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported"); |
| } |
| |
| /* Initialize all objects required to run the test */ |
| initTest(); |
| |
| /* Initialize per-sample filler program */ |
| initPerSampleFillerProgramObject(); |
| |
| /* Iterate through all texture/view texture target combinations */ |
| TextureViewUtilities::_compatible_texture_target_pairs_const_iterator texture_target_iterator; |
| TextureViewUtilities::_compatible_texture_target_pairs texture_target_pairs = |
| TextureViewUtilities::getLegalTextureAndViewTargetCombinations(); |
| |
| for (texture_target_iterator = texture_target_pairs.begin(); texture_target_iterator != texture_target_pairs.end(); |
| ++texture_target_iterator) |
| { |
| const glw::GLenum parent_texture_target = texture_target_iterator->first; |
| const glw::GLenum view_texture_target = texture_target_iterator->second; |
| |
| /* Initialize parent texture */ |
| initTextureObject(false /* is_view_texture */, parent_texture_target, view_texture_target); |
| |
| /* Initialize view */ |
| initTextureObject(true /* is_view_texture */, parent_texture_target, view_texture_target); |
| |
| /* Initialize contents of the parent texture */ |
| initParentTextureContents(); |
| |
| /* Initialize iteration-specific test program object */ |
| initIterationSpecificProgramObject(); |
| |
| /* Run the actual test */ |
| bool status = executeTest(); |
| |
| if (!status) |
| { |
| has_failed = true; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "Test case failed." << tcu::TestLog::EndMessage; |
| } |
| else |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Test case succeeded." << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| if (!has_failed) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| return STOP; |
| } |
| |
| /** De-allocates existing reference color storage (if one already exists) and |
| * allocates a new one using user-provided properties. |
| * |
| * @param n_layers Amount of layers to consider. Use a value of 1 for non-arrayed |
| * texture targets. |
| * @param n_faces Amount of faces to consider. Use a value of 1 for non-CM |
| * texture targets. |
| * @param n_mipmaps Amount of mip-maps to consider. Use a value of 1 for non-mipmapped |
| * texture targets. |
| * @param n_samples Amount of samples to consider. Use a value of 1 for single-sampled |
| * texture targets. |
| **/ |
| void TextureViewTestViewSampling::resetReferenceColorStorage(unsigned int n_layers, unsigned int n_faces, |
| unsigned int n_mipmaps, unsigned int n_samples) |
| { |
| /* Sanity checks */ |
| DE_ASSERT(n_layers >= 1); |
| DE_ASSERT(n_faces >= 1); |
| DE_ASSERT(n_mipmaps >= 1); |
| DE_ASSERT(n_samples >= 1); |
| |
| /* Allocate the descriptor if it's the first time the test will be |
| * attempting to access it */ |
| if (m_reference_color_storage == DE_NULL) |
| { |
| m_reference_color_storage = new _reference_color_storage(n_faces, n_layers, n_mipmaps, n_samples); |
| } |
| else |
| { |
| /* The descriptor's already there so we only need to update the properties */ |
| m_reference_color_storage->n_faces = n_faces; |
| m_reference_color_storage->n_layers = n_layers; |
| m_reference_color_storage->n_mipmaps = n_mipmaps; |
| m_reference_color_storage->n_samples = n_samples; |
| } |
| |
| /* If there's any data descriptor found allocated at this point, |
| * release it */ |
| if (m_reference_color_storage->data != DE_NULL) |
| { |
| delete[] m_reference_color_storage->data; |
| |
| m_reference_color_storage->data = DE_NULL; |
| } |
| |
| m_reference_color_storage->data = new tcu::Vec4[n_layers * n_faces * n_mipmaps * n_samples]; |
| } |
| |
| /** Assigns user-specified reference color to a specific sample of a layer/face's mip-map. |
| * |
| * This function throws an assertion failure if the requested layer/face/mip-map/sample index |
| * is invalid. |
| * |
| * @param n_layer Layer index to use for the association. Use a value of 0 for non-arrayed texture |
| * targets. |
| * @param n_face Face index to use for the association. Use a value of 0 for non-CM texture targets. |
| * @param n_mipmap Mip-map index to use for the association. Use a value of 0 for non-mipmapped texture |
| * targets. |
| * @param n_sample Sample index to use for the association. Use a value of 0 for single-sampled texture |
| * targets. |
| * @param color Color to associate with the specified sample. |
| **/ |
| void TextureViewTestViewSampling::setReferenceColor(unsigned int n_layer, unsigned int n_face, unsigned int n_mipmap, |
| unsigned int n_sample, tcu::Vec4 color) |
| { |
| DE_ASSERT(m_reference_color_storage != DE_NULL); |
| if (m_reference_color_storage != DE_NULL) |
| { |
| DE_ASSERT(n_face < m_reference_color_storage->n_faces); |
| DE_ASSERT(n_layer < m_reference_color_storage->n_layers); |
| DE_ASSERT(n_mipmap < m_reference_color_storage->n_mipmaps); |
| DE_ASSERT(n_sample < m_reference_color_storage->n_samples); |
| |
| /* Hierarchy is: |
| * |
| * layers -> faces -> mipmaps -> samples */ |
| const unsigned int index = |
| n_layer * (m_reference_color_storage->n_faces * m_reference_color_storage->n_mipmaps * |
| m_reference_color_storage->n_samples) + |
| n_face * (m_reference_color_storage->n_mipmaps * m_reference_color_storage->n_samples) + |
| n_mipmap * (m_reference_color_storage->n_samples) + n_sample; |
| |
| m_reference_color_storage->data[index] = color; |
| } |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| **/ |
| TextureViewTestViewClasses::TextureViewTestViewClasses(deqp::Context& context) |
| : TestCase(context, "view_classes", "Verifies view sampling works correctly. Tests all valid" |
| " texture/view internalformat combinations.") |
| , m_bo_id(0) |
| , m_po_id(0) |
| , m_to_id(0) |
| , m_to_temp_id(0) |
| , m_vao_id(0) |
| , m_view_to_id(0) |
| , m_vs_id(0) |
| , m_decompressed_mipmap_data(DE_NULL) |
| , m_mipmap_data(DE_NULL) |
| , m_bo_size(0) |
| , m_has_test_failed(false) |
| , m_texture_height(4) |
| , m_texture_unit_for_parent_texture(GL_TEXTURE0) |
| , m_texture_unit_for_view_texture(GL_TEXTURE1) |
| , m_texture_width(4) |
| , m_view_data_offset(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all buffers and GL objects that may have been created |
| * during test execution. Also restores GL state that may have been modified. |
| **/ |
| void TextureViewTestViewClasses::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id); |
| |
| m_bo_id = 0; |
| } |
| |
| if (m_decompressed_mipmap_data != DE_NULL) |
| { |
| delete[] m_decompressed_mipmap_data; |
| |
| m_decompressed_mipmap_data = DE_NULL; |
| } |
| |
| if (m_mipmap_data != DE_NULL) |
| { |
| delete[] m_mipmap_data; |
| |
| m_mipmap_data = DE_NULL; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| |
| if (m_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| |
| m_to_id = 0; |
| } |
| |
| if (m_to_temp_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_temp_id); |
| |
| m_to_temp_id = 0; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| |
| if (m_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_to_id); |
| |
| m_view_to_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| |
| /* Bring back the default pixel storage settings that the test may have modified. */ |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 4); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); |
| |
| /* Restore rasterization */ |
| gl.enable(GL_RASTERIZER_DISCARD); |
| } |
| |
| /** Reads user-specified amount of components and stores it in user-provided location, |
| * according to user-defined format (snorm, unorm, etc.) and component size. |
| * |
| * This function assumes component sizes are aligned on by boundary (that is: size % 8 |
| * equals 0 for all components). An assertion failure will occur if this requirement is |
| * not met. |
| * This function throws TestError exception if any of the requested component sizes |
| * or format is not supported. |
| * |
| * @param data Raw data buffer to read the data from. |
| * @param n_components Amount of components to read. |
| * @param component_sizes 4 ints subsequently defining component size for R/G/B/A channels. |
| * Must not be NULL. |
| * @param format Format to be used for data retrieval. This defines data format of |
| * the underlying components (for instance: for UNORMs we need to |
| * divide the read ubyte/ushort/uint data by maximum value allowed for |
| * the type minus one) |
| * @param result Location to store the read components. Must not be NULL. Must be |
| * large enough to hold requested amount of components of user-specified |
| * component size. |
| * |
| **/ |
| void TextureViewTestViewClasses::getComponentDataForByteAlignedInternalformat(const unsigned char* data, |
| const unsigned int n_components, |
| const unsigned int* component_sizes, |
| const _format format, void* result) |
| { |
| float* result_float = (float*)result; |
| signed int* result_sint = (signed int*)result; |
| unsigned int* result_uint = (unsigned int*)result; |
| |
| /* Sanity checks: we assume the components are aligned on byte boundary. */ |
| DE_ASSERT((component_sizes[0] % 8) == 0 && (component_sizes[1] % 8) == 0 && (component_sizes[2] % 8) == 0 && |
| (component_sizes[3] % 8) == 0); |
| |
| for (unsigned int n_component = 0; n_component < n_components; |
| data += (component_sizes[n_component] >> 3 /* 8 bits/byte */), ++n_component) |
| { |
| switch (format) |
| { |
| case FORMAT_FLOAT: |
| { |
| switch (component_sizes[n_component]) |
| { |
| case 16: |
| result_float[n_component] = deFloat16To32(*(const deFloat16*)data); |
| break; |
| case 32: |
| result_float[n_component] = *(float*)data; |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported component size"); |
| } |
| |
| break; |
| } |
| |
| case FORMAT_SIGNED_INTEGER: |
| { |
| switch (component_sizes[n_component]) |
| { |
| case 8: |
| result_sint[n_component] = *(signed char*)data; |
| break; |
| case 16: |
| result_sint[n_component] = *(signed short*)data; |
| break; |
| case 32: |
| result_sint[n_component] = *(signed int*)data; |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported component size"); |
| } |
| |
| break; |
| } |
| |
| case FORMAT_SNORM: |
| { |
| switch (component_sizes[n_component]) |
| { |
| case 8: |
| result_float[n_component] = float(*(signed char*)data) / 127.0f; |
| break; |
| case 16: |
| result_float[n_component] = float(*(signed short*)data) / 32767.0f; |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported component size"); |
| } |
| |
| if (result_float[n_component] < -1.0f) |
| { |
| result_float[n_component] = -1.0f; |
| } |
| |
| break; |
| } |
| |
| case FORMAT_UNORM: |
| { |
| switch (component_sizes[n_component]) |
| { |
| case 8: |
| result_float[n_component] = float(*((unsigned char*)data)) / 255.0f; |
| break; |
| case 16: |
| result_float[n_component] = float(*((unsigned short*)data)) / 65535.0f; |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported component size"); |
| } |
| |
| break; |
| } |
| |
| case FORMAT_UNSIGNED_INTEGER: |
| { |
| switch (component_sizes[n_component]) |
| { |
| case 8: |
| result_uint[n_component] = *(unsigned char*)data; |
| break; |
| case 16: |
| result_uint[n_component] = *(unsigned short*)data; |
| break; |
| case 32: |
| result_uint[n_component] = *(unsigned int*)data; |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported component size"); |
| } |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized mip-map format"); |
| } |
| } /* switch (view_format) */ |
| } /* for (all components) */ |
| } |
| |
| /** Initializes buffer object storage of sufficient size to hold data that will be |
| * XFBed out by the test's vertex shader, given user-specified parent texture & |
| * view's internalformats. |
| * |
| * Throws TestError exceptions if GL calls fail. |
| * |
| * @param texture_internalformat Internalformat used by the parent texture object, |
| * from which the view will be created. |
| * @param view_internalformat Internalformat that will be used by the texture view. |
| **/ |
| void TextureViewTestViewClasses::initBufferObject(glw::GLenum texture_internalformat, glw::GLenum view_internalformat) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Calculate how much size we will need to read the XFBed data. Each sampled data |
| * will either end up stored in a vecX, ivecX or uvecX (where X stands for amount |
| * of components supported by considered internalformat), so we can assume it will |
| * take a sizeof(float) = sizeof(int) = sizeof(unsigned int) |
| */ |
| const unsigned int parent_texture_n_components = |
| TextureViewUtilities::getAmountOfComponentsForInternalformat(texture_internalformat); |
| const unsigned int view_texture_n_components = |
| TextureViewUtilities::getAmountOfComponentsForInternalformat(view_internalformat); |
| |
| /* Configure buffer object storage. |
| * |
| * NOTE: We do not care about the data type of the stored data, since sizes of the |
| * types we're interested in (floats, ints and uints) match. |
| */ |
| DE_ASSERT(sizeof(float) == sizeof(unsigned int) && sizeof(float) == sizeof(int)); |
| |
| m_bo_size = |
| static_cast<unsigned int>(parent_texture_n_components * sizeof(float) * m_texture_height * m_texture_width + |
| view_texture_n_components * sizeof(float) * m_texture_height * m_texture_width); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_size, DE_NULL, /* data */ |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); |
| |
| /* For XFB, we'll be outputting data sampled from both the texture and the view. |
| * Sampled texture data will go to the first half of the buffer, and the corresponding |
| * view data will go to the one half. |
| * |
| * Store the offset, from which the view's data will start so that we can correctly |
| * configure buffer object bindings in initProgramObject() |
| **/ |
| m_view_data_offset = |
| static_cast<unsigned int>(parent_texture_n_components * sizeof(float) * m_texture_height * m_texture_width); |
| } |
| |
| /** Initializes a program object that should be used for the test, given |
| * user-specified texture and view internalformats. |
| * |
| * @param texture_internalformat Internalformat used by the parent texture object, |
| * from which the view will be created. |
| * @param view_internalformat Internalformat that will be used by the texture view. |
| **/ |
| void TextureViewTestViewClasses::initProgramObject(glw::GLenum texture_internalformat, glw::GLenum view_internalformat) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Determine which samplers we should be using for sampling both textures */ |
| const unsigned int texture_n_components = |
| TextureViewUtilities::getAmountOfComponentsForInternalformat(texture_internalformat); |
| const _sampler_type texture_sampler_type = |
| TextureViewUtilities::getSamplerTypeForInternalformat(texture_internalformat); |
| const char* texture_sampler_data_type_glsl = |
| TextureViewUtilities::getGLSLDataTypeForSamplerType(texture_sampler_type, texture_n_components); |
| const char* texture_sampler_glsl = TextureViewUtilities::getGLSLTypeForSamplerType(texture_sampler_type); |
| const char* texture_swizzle_glsl = |
| (texture_n_components == 4) ? "xyzw" : |
| (texture_n_components == 3) ? "xyz" : (texture_n_components == 2) ? "xy" : "x"; |
| const unsigned int view_n_components = |
| TextureViewUtilities::getAmountOfComponentsForInternalformat(view_internalformat); |
| const _sampler_type view_sampler_type = TextureViewUtilities::getSamplerTypeForInternalformat(view_internalformat); |
| const char* view_sampler_data_type_glsl = |
| TextureViewUtilities::getGLSLDataTypeForSamplerType(view_sampler_type, view_n_components); |
| const char* view_sampler_glsl = TextureViewUtilities::getGLSLTypeForSamplerType(view_sampler_type); |
| const char* view_swizzle_glsl = |
| (view_n_components == 4) ? "xyzw" : (view_n_components == 3) ? "xyz" : (view_n_components == 2) ? "xy" : "x"; |
| |
| /* Form vertex shader body */ |
| const char* token_texture_data_type = "TEXTURE_DATA_TYPE"; |
| const char* token_texture_sampler = "TEXTURE_SAMPLER"; |
| const char* token_texture_swizzle = "TEXTURE_SWIZZLE"; |
| const char* token_view_data_type = "VIEW_DATA_TYPE"; |
| const char* token_view_sampler = "VIEW_SAMPLER"; |
| const char* token_view_swizzle = "VIEW_SWIZZLE"; |
| const char* vs_template_body = "#version 400\n" |
| "\n" |
| "uniform TEXTURE_SAMPLER texture;\n" |
| "uniform VIEW_SAMPLER view;\n" |
| "\n" |
| "out TEXTURE_DATA_TYPE out_texture_data;\n" |
| "out VIEW_DATA_TYPE out_view_data;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " ivec2 uv = ivec2(gl_VertexID % 4,\n" |
| " gl_VertexID / 4);\n" |
| "\n" |
| " out_texture_data = texelFetch(texture, uv, 0).TEXTURE_SWIZZLE;\n" |
| " out_view_data = texelFetch(view, uv, 0).VIEW_SWIZZLE;\n" |
| "}\n"; |
| |
| std::size_t token_position = std::string::npos; |
| std::string vs_body = vs_template_body; |
| |
| while ((token_position = vs_body.find(token_texture_data_type)) != std::string::npos) |
| { |
| vs_body.replace(token_position, strlen(token_texture_data_type), texture_sampler_data_type_glsl); |
| } |
| |
| while ((token_position = vs_body.find(token_texture_sampler)) != std::string::npos) |
| { |
| vs_body.replace(token_position, strlen(token_texture_sampler), texture_sampler_glsl); |
| } |
| |
| while ((token_position = vs_body.find(token_texture_swizzle)) != std::string::npos) |
| { |
| vs_body.replace(token_position, strlen(token_texture_swizzle), texture_swizzle_glsl); |
| } |
| |
| while ((token_position = vs_body.find(token_view_data_type)) != std::string::npos) |
| { |
| vs_body.replace(token_position, strlen(token_view_data_type), view_sampler_data_type_glsl); |
| } |
| |
| while ((token_position = vs_body.find(token_view_sampler)) != std::string::npos) |
| { |
| vs_body.replace(token_position, strlen(token_view_sampler), view_sampler_glsl); |
| } |
| |
| while ((token_position = vs_body.find(token_view_swizzle)) != std::string::npos) |
| { |
| vs_body.replace(token_position, strlen(token_view_swizzle), view_swizzle_glsl); |
| } |
| |
| /* Compile the shader */ |
| glw::GLint compile_status = GL_FALSE; |
| const char* vs_body_raw_ptr = vs_body.c_str(); |
| |
| gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| gl.compileShader(m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| TCU_FAIL("Shader compilation failed"); |
| } |
| |
| /* Configure test program object for XFB */ |
| const char* varying_names[] = { "out_texture_data", "out_view_data" }; |
| const unsigned int n_varying_names = sizeof(varying_names) / sizeof(varying_names[0]); |
| |
| gl.transformFeedbackVaryings(m_po_id, n_varying_names, varying_names, GL_SEPARATE_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); |
| |
| /* Configure buffer object bindings for XFB */ |
| gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index for 'out_texture_data' */ |
| m_bo_id, 0, /* offset */ |
| m_view_data_offset); /* size */ |
| gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, /* index for 'out_view_data' */ |
| m_bo_id, m_view_data_offset, /* offset */ |
| m_bo_size - m_view_data_offset); /* size */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() call(s) failed."); |
| |
| /* Link the program object */ |
| glw::GLint link_status = GL_FALSE; |
| |
| gl.linkProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status != GL_TRUE) |
| { |
| TCU_FAIL("Program linking failed."); |
| } |
| |
| /* Configure sampler uniforms */ |
| glw::GLint texture_uniform_location = gl.getUniformLocation(m_po_id, "texture"); |
| glw::GLint view_uniform_location = gl.getUniformLocation(m_po_id, "view"); |
| |
| if (texture_uniform_location == -1) |
| { |
| TCU_FAIL("'texture' uniform is considered inactive which is invalid"); |
| } |
| |
| if (view_uniform_location == -1) |
| { |
| TCU_FAIL("'view' uniform is considered inactive which is invalid"); |
| } |
| |
| gl.useProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| gl.uniform1i(texture_uniform_location, m_texture_unit_for_parent_texture - GL_TEXTURE0); |
| gl.uniform1i(view_uniform_location, m_texture_unit_for_view_texture - GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call(s) failed."); |
| } |
| |
| /** Creates GL objects required to run the test, as well as modifies GL |
| * configuration (pixel pack/unpack settings, enables 'rasterizer discard' mode) |
| * in order for the test to run properly. |
| **/ |
| void TextureViewTestViewClasses::initTest() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate objects that will be used by all test iterations. |
| * |
| * Note that we're not generating texture objects here. This is owing to the fact |
| * we'll be using immutable textures and it makes more sense to generate the objects |
| * in initTexture() instead. |
| **/ |
| gl.genBuffers(1, &m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); |
| |
| m_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); |
| |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); |
| |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed."); |
| |
| /* Attach the vertex shader to the program object */ |
| gl.attachShader(m_po_id, m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed."); |
| |
| /* Configure general buffer object binding. Indiced bindings will be configured |
| * in initProgramObject() |
| */ |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed."); |
| |
| /* Bind the VAO */ |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); |
| |
| /* Modify pack & unpack alignment settings */ |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 1); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call(s) failed."); |
| |
| /* Disable rasterizatino */ |
| gl.enable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed."); |
| } |
| |
| /** Generates and initializes storage of either the parent texture object or the |
| * texture view, using user-specified internalformat. |
| * |
| * @param should_init_parent_texture true to initialize parent texture object storage, |
| * false to configure texture view. |
| * @param internalformat Internalformat to use for the process. |
| * @param viewformat Internalformat that will be used by "view" texture. |
| * |
| **/ |
| void TextureViewTestViewClasses::initTextureObject(bool should_init_parent_texture, glw::GLenum texture_internalformat, |
| glw::GLenum view_internalformat) |
| { |
| glw::GLenum cached_view_internalformat = view_internalformat; |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLuint* to_id_ptr = (should_init_parent_texture) ? &m_to_id : &m_view_to_id; |
| |
| /* If the object we're about to initialize has already been created, delete it first. */ |
| if (*to_id_ptr != 0) |
| { |
| gl.deleteTextures(1, to_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call failed."); |
| |
| *to_id_ptr = 0; |
| } |
| |
| /* Generate a new texture object */ |
| gl.genTextures(1, to_id_ptr); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); |
| |
| /* Initialize the object */ |
| if (should_init_parent_texture) |
| { |
| gl.bindTexture(GL_TEXTURE_2D, *to_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ |
| texture_internalformat, m_texture_width, m_texture_height); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| } |
| else |
| { |
| gl.textureView(m_view_to_id, GL_TEXTURE_2D, m_to_id, view_internalformat, 0, /* minlevel */ |
| 1, /* numlevels */ |
| 0, /* minlayer */ |
| 1); /* numlayers */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| } |
| |
| if (should_init_parent_texture) |
| { |
| /* We need to fill the base mip-map with actual contents. Calculate how much |
| * data we will need to fill a 4x4 mip-map, given the requested internalformat. |
| */ |
| bool is_internalformat_compressed = TextureViewUtilities::isInternalformatCompressed(texture_internalformat); |
| glw::GLenum internalformat_to_use = GL_NONE; |
| |
| if (is_internalformat_compressed) |
| { |
| /* In order to initialize texture objects defined with a compressed internalformat |
| * using raw decompressed data, we need to override caller-specified internalformat |
| * with an internalformat that will describe decompressed data. The data will then |
| * be converted by GL to the compressed internalformat that was used for the previous |
| * glTexStorage2D() call. |
| **/ |
| _format format = TextureViewUtilities::getFormatOfInternalformat(texture_internalformat); |
| |
| if (format == FORMAT_FLOAT) |
| { |
| internalformat_to_use = GL_RGBA32F; |
| } |
| else |
| { |
| DE_ASSERT(format == FORMAT_UNORM || format == FORMAT_SNORM); |
| |
| internalformat_to_use = GL_RGBA8; |
| } |
| |
| view_internalformat = internalformat_to_use; |
| } |
| else |
| { |
| internalformat_to_use = texture_internalformat; |
| } |
| |
| /* Allocate the buffer. |
| * |
| * NOTE: This buffer is used in verifyResults(). When no longer needed, it will either |
| * be deallocated there or in deinit(). |
| **/ |
| glw::GLenum format_to_use = TextureViewUtilities::getGLFormatOfInternalformat(internalformat_to_use); |
| glw::GLenum type_to_use = TextureViewUtilities::getTypeCompatibleWithInternalformat(internalformat_to_use); |
| const glw::GLenum view_type = TextureViewUtilities::getTypeCompatibleWithInternalformat(view_internalformat); |
| |
| /* For some internalformats, we need to use a special data type in order to avoid |
| * implicit data conversion during glTexSubImage2D() call. |
| */ |
| switch (texture_internalformat) |
| { |
| case GL_R11F_G11F_B10F: |
| type_to_use = GL_UNSIGNED_INT_10F_11F_11F_REV; |
| break; |
| case GL_RGB9_E5: |
| type_to_use = GL_UNSIGNED_INT_5_9_9_9_REV; |
| break; |
| case GL_RGB10_A2: |
| type_to_use = GL_UNSIGNED_INT_2_10_10_10_REV; |
| break; |
| |
| /* Fall-through for other internalformats! */ |
| } /* switch (texture_internalformat) */ |
| |
| /* Carry on */ |
| const unsigned int mipmap_raw_size = TextureViewUtilities::getTextureDataSize( |
| internalformat_to_use, type_to_use, m_texture_width, m_texture_height); |
| |
| if (m_mipmap_data != NULL) |
| { |
| delete[] m_mipmap_data; |
| |
| m_mipmap_data = NULL; |
| } |
| |
| m_mipmap_data = new unsigned char[mipmap_raw_size]; |
| |
| /* Prepare data for texture */ |
| memset(m_mipmap_data, 0, mipmap_raw_size); |
| |
| switch (view_type) |
| { |
| case GL_BYTE: |
| { |
| glw::GLbyte* buffer = (glw::GLbyte*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 1; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = static_cast<glw::GLbyte>(i - 128); |
| } |
| |
| break; |
| } |
| |
| case GL_SHORT: |
| { |
| glw::GLshort* buffer = (glw::GLshort*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 2; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = static_cast<glw::GLshort>(i - 0xC000); // 0xC000 = (fp16) -2 makes this non de-norm |
| } |
| |
| break; |
| } |
| |
| case GL_INT: |
| { |
| glw::GLint* buffer = (glw::GLint*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 4; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = i - 128; |
| } |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_BYTE: |
| { |
| glw::GLubyte* buffer = (glw::GLubyte*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 1; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = static_cast<glw::GLubyte>(i); |
| } |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_SHORT: |
| { |
| glw::GLushort* buffer = (glw::GLushort*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 2; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = static_cast<glw::GLushort>(i); |
| } |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT: |
| { |
| glw::GLuint* buffer = (glw::GLuint*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 4; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = i; |
| } |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_24_8: |
| { |
| glw::GLuint* buffer = (glw::GLuint*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 4; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = (i << 8) | (0xaa); |
| } |
| |
| break; |
| } |
| |
| case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: |
| { |
| glw::GLfloat* float_buffer = (glw::GLfloat*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 8; |
| glw::GLuint* uint_buffer = (glw::GLuint*)(m_mipmap_data + 4); |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| float_buffer[i * 2] = (float)i - 128; |
| uint_buffer[i * 2] = (i << 8) | (0xaa); |
| } |
| |
| break; |
| } |
| |
| case GL_HALF_FLOAT: |
| { |
| tcu::Float16* buffer = (tcu::Float16*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 2; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| float value = (float)i - 128; |
| |
| buffer[i] = (tcu::Float16)value; |
| } |
| |
| break; |
| } |
| |
| case GL_FLOAT: |
| { |
| glw::GLfloat* float_buffer = (glw::GLfloat*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 4; |
| |
| float offset = (cached_view_internalformat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) ? 0.0f : -128.0f; |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| float_buffer[i] = (float)i + offset; |
| } |
| |
| break; |
| } |
| |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| { |
| glw::GLuint* buffer = (glw::GLuint*)m_mipmap_data; |
| const glw::GLuint n_total_components = mipmap_raw_size / 4; |
| |
| for (glw::GLuint i = 0; i < n_total_components; ++i) |
| { |
| buffer[i] = i | (i << 8) | (i << 16); |
| } |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture view type"); |
| } |
| } /* switch (view_type) */ |
| |
| /* BPTC_FLOAT view class is a special case that needs an extra step. Signed and |
| * unsigned internal formats use different encodings, so instead of passing |
| * "regular" 32-bit floating-point data, we need to convert the values we initialized |
| * above to an actual BPTC representation. Since the encodings differ, we should |
| * compress these values using the internalformat that we will be later using for the |
| * texture view. |
| */ |
| unsigned int imageSize_to_use = 0; |
| bool use_glCompressedTexSubImage2D_call = false; |
| |
| if ((cached_view_internalformat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT || |
| cached_view_internalformat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) && |
| cached_view_internalformat != texture_internalformat) |
| { |
| /* Create a temporary texture object we'll use to compress the floating-point data. */ |
| gl.genTextures(1, &m_to_temp_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_to_temp_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Initialize compressed storage */ |
| gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ |
| cached_view_internalformat, m_texture_width, m_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| /* Submit floating-point decompressed data */ |
| gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */ |
| 0, /* xoffset */ |
| 0, /* yoffset */ |
| m_texture_width, m_texture_height, GL_RGB, GL_FLOAT, m_mipmap_data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed."); |
| |
| /* Extract the compressed version */ |
| gl.getCompressedTexImage(GL_TEXTURE_2D, 0, /* level */ |
| m_mipmap_data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetCompressedTexImage() call failed."); |
| |
| /* Delete the temporary texture object */ |
| gl.deleteTextures(1, &m_to_temp_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call failed."); |
| |
| m_to_temp_id = 0; |
| |
| /* Revert to previous 2D texture binding */ |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Make sure upcoming glCompressedTexSubImage2D() call is made with sensible arguments */ |
| imageSize_to_use = (unsigned int)ceil((float)m_texture_width / 4.0f) * |
| (unsigned int)ceil((float)m_texture_height / 4.0f) * 16; /* block size */ |
| use_glCompressedTexSubImage2D_call = true; |
| } |
| |
| /* Fill the mip-map with data */ |
| if (use_glCompressedTexSubImage2D_call) |
| { |
| gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, /* level */ |
| 0, /* xoffset */ |
| 0, /* yoffset */ |
| m_texture_width, m_texture_height, texture_internalformat, imageSize_to_use, |
| m_mipmap_data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexSubImage2D() call failed."); |
| } |
| else |
| { |
| gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */ |
| 0, /* xoffset */ |
| 0, /* yoffset */ |
| m_texture_width, m_texture_height, format_to_use, type_to_use, m_mipmap_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed."); |
| } |
| } |
| |
| /* Make sure the texture object is complete */ |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST); /* we're using texelFetch() so no mipmaps needed */ |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call(s) failed."); |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestViewClasses::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Only execute the test if GL_ARB_texture_view is supported */ |
| if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_texture_view")) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported, skipping."); |
| } |
| |
| /* Create all GL objects required to run the test */ |
| initTest(); |
| |
| /* Iterate through all valid "texture internalformat + view internalformat" combinations */ |
| TextureViewUtilities::_compatible_internalformat_pairs_const_iterator internalformat_combination_iterator; |
| TextureViewUtilities::_compatible_internalformat_pairs internalformat_combinations = |
| TextureViewUtilities::getLegalTextureAndViewInternalformatCombinations(); |
| |
| for (internalformat_combination_iterator = internalformat_combinations.begin(); |
| internalformat_combination_iterator != internalformat_combinations.end(); |
| internalformat_combination_iterator++) |
| { |
| TextureViewUtilities::_internalformat_pair internalformat_pair = *internalformat_combination_iterator; |
| glw::GLenum texture_internalformat = internalformat_pair.first; |
| glw::GLenum view_internalformat = internalformat_pair.second; |
| |
| /* Initialize parent texture object storage */ |
| initTextureObject(true, /* should_init_parent_texture */ |
| texture_internalformat, view_internalformat); |
| |
| /* Create the texture view */ |
| initTextureObject(false, /* should_init_parent_texture */ |
| texture_internalformat, view_internalformat); |
| |
| /* Initialize buffer object storage so that it's large enough to |
| * hold the result data. |
| **/ |
| initBufferObject(texture_internalformat, view_internalformat); |
| |
| /* Create the program object we'll use for the test */ |
| initProgramObject(texture_internalformat, view_internalformat); |
| |
| /* Configure texture bindings */ |
| gl.activeTexture(m_texture_unit_for_parent_texture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.activeTexture(m_texture_unit_for_view_texture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Run the test program */ |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); |
| { |
| gl.drawArrays(GL_POINTS, 0 /* first */, m_texture_width * m_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); |
| |
| /* Retrieve the results */ |
| const unsigned char* result_bo_data_ptr = |
| (const unsigned char*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); |
| const unsigned char* result_texture_data_ptr = result_bo_data_ptr; |
| const unsigned char* result_view_data_ptr = result_bo_data_ptr + m_view_data_offset; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed."); |
| |
| /* Verify the retrieved values are valid */ |
| verifyResultData(texture_internalformat, view_internalformat, result_texture_data_ptr, result_view_data_ptr); |
| |
| /* Unmap the buffer object */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); |
| } /* for (all internalformat combinations) */ |
| |
| if (m_has_test_failed) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| |
| return STOP; |
| } |
| |
| /** Verifies the data XFBed out by the test's vertex shader is valid. |
| * |
| * @param texture_internalformat Internalformat that was used to define storage |
| * of the parent texture object. |
| * @param view_internalformat Internalformat that was used to define texture |
| * view. |
| * @param texture_data_ptr Data, as XFBed out by the vertex shader, that was |
| * built by texelFetch() calls operating on the parent |
| * texture object. |
| * @param view_data_ptr Data, as XFBed out by the vertex shader, that was |
| * built by texelFetch() calls operating on the texture |
| * view. |
| * |
| **/ |
| void TextureViewTestViewClasses::verifyResultData(glw::GLenum texture_internalformat, glw::GLenum view_internalformat, |
| const unsigned char* texture_data_ptr, |
| const unsigned char* view_data_ptr) |
| { |
| const char* texture_internalformat_string = TextureViewUtilities::getInternalformatString(texture_internalformat); |
| const char* view_internalformat_string = TextureViewUtilities::getInternalformatString(view_internalformat); |
| |
| /* For quite a number of cases, we can do a plain memcmp() applied to sampled texture/view data. |
| * If both buffers are a match, we're OK. |
| */ |
| bool has_failed = false; |
| const unsigned char* mipmap_data = DE_NULL; |
| |
| if (memcmp(texture_data_ptr, view_data_ptr, m_view_data_offset) != 0) |
| { |
| /* Iterate over all texel components. |
| * |
| * The approach we're taking here works as follows: |
| * |
| * 1) Calculate what values should be sampled for each component using input mipmap |
| * data. |
| * 2) Compare the reference values against the values returned when sampling the view. |
| * |
| * Note that in step 2) we're dealing with data that is returned by float/int/uint samplers, |
| * so we need to additionally process the data that we obtain by "casting" input data to |
| * the view's internalformat before we can perform the comparison. |
| * |
| * Finally, if the reference values are calculated for compressed data, we decompress it |
| * to GL_R8/GL_RG8/GL_RGB8/GL_RGBA8 internalformat first, depending on how many components |
| * the compressed internalformat supports. |
| **/ |
| bool can_continue = true; |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Determine a few important properties first */ |
| const bool is_view_internalformat_compressed = |
| TextureViewUtilities::isInternalformatCompressed(view_internalformat); |
| unsigned int n_bits_per_view_texel = 0; |
| |
| const unsigned int n_view_components = |
| TextureViewUtilities::getAmountOfComponentsForInternalformat(view_internalformat); |
| _format texture_format = TextureViewUtilities::getFormatOfInternalformat(texture_internalformat); |
| |
| unsigned int view_component_sizes[4] = { 0 }; |
| _format view_format = TextureViewUtilities::getFormatOfInternalformat(view_internalformat); |
| |
| if (!is_view_internalformat_compressed) |
| { |
| TextureViewUtilities::getComponentSizeForInternalformat(view_internalformat, view_component_sizes); |
| |
| n_bits_per_view_texel = |
| view_component_sizes[0] + view_component_sizes[1] + view_component_sizes[2] + view_component_sizes[3]; |
| } |
| else |
| { |
| if (texture_internalformat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT || |
| texture_internalformat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) |
| { |
| /* Each component of decompressed data will be retrieved as a 32-bit FP */ |
| for (unsigned int n_component = 0; n_component < n_view_components; ++n_component) |
| { |
| view_component_sizes[n_component] = 32 /* bits per byte */; |
| } |
| |
| n_bits_per_view_texel = 32 /* bits per byte */ * n_view_components; |
| } |
| else |
| { |
| /* Each component of decompressed data is stored as either signed or unsigned |
| * byte. */ |
| for (unsigned int n_component = 0; n_component < n_view_components; ++n_component) |
| { |
| view_component_sizes[n_component] = 8 /* bits per byte */; |
| } |
| |
| n_bits_per_view_texel = 8 /* bits per byte */ * n_view_components; |
| } |
| } |
| |
| /* If we need to use compressed data as reference, we need to ask GL to decompress |
| * the mipmap data using view-specific internalformat. |
| */ |
| mipmap_data = m_mipmap_data; |
| |
| if (is_view_internalformat_compressed) |
| { |
| /* Deallocate the buffer if necessary just in case */ |
| if (m_decompressed_mipmap_data != DE_NULL) |
| { |
| delete[] m_decompressed_mipmap_data; |
| |
| m_decompressed_mipmap_data = DE_NULL; |
| } |
| |
| m_decompressed_mipmap_data = |
| new unsigned char[m_texture_width * m_texture_height * (n_bits_per_view_texel >> 3)]; |
| |
| glw::GLuint reference_tex_id = m_to_id; |
| if (texture_internalformat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT || |
| texture_internalformat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) |
| { |
| // Encodings of SIGNED and UNSIGNED BPTC compressed texture are not compatible |
| // even though they are in the same view class. Since the "view" texture contains |
| // the correct encoding for the results we use that as a reference instead of the |
| // incompatible parent encoded. |
| reference_tex_id = m_view_to_id; |
| } |
| gl.bindTexture(GL_TEXTURE_2D, reference_tex_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.getTexImage(GL_TEXTURE_2D, 0, /* level */ |
| (n_view_components == 4) ? |
| GL_RGBA : |
| (n_view_components == 3) ? GL_RGB : (n_view_components == 2) ? GL_RG : GL_RED, |
| (texture_format == FORMAT_SNORM) ? |
| GL_BYTE : |
| (texture_format == FORMAT_FLOAT) ? GL_FLOAT : GL_UNSIGNED_BYTE, |
| m_decompressed_mipmap_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexImage() call failed."); |
| |
| mipmap_data = m_decompressed_mipmap_data; |
| } |
| |
| for (unsigned int n_texel = 0; n_texel < m_texture_height * m_texture_width && can_continue; ++n_texel) |
| { |
| /* NOTE: Vertex shader stores the sampled contents of a view texture as a |
| * vec4/ivec4/uvec4. This means that each comonent in view_data_ptr |
| * always takes sizeof(float) = sizeof(int) = sizeof(uint) bytes. |
| * |
| * NOTE: We cast input mip-map's data to view's internalformat, which is |
| * why we're assuming each components takes n_bits_per_view_texel |
| * bits instead of n_bits_per_mipmap_texel. |
| */ |
| const unsigned char* mipmap_texel_data = |
| mipmap_data + (n_bits_per_view_texel >> 3 /* 8 bits/byte */) * n_texel; |
| float reference_components_float[4] = { 0 }; |
| signed int reference_components_int[4] = { 0 }; |
| unsigned int reference_components_uint[4] = { 0 }; |
| float view_components_float[4] = { 0 }; |
| signed int view_components_int[4] = { 0 }; |
| unsigned int view_components_uint[4] = { 0 }; |
| _sampler_type view_sampler_type = |
| TextureViewUtilities::getSamplerTypeForInternalformat(view_internalformat); |
| const unsigned char* view_texel_data = view_data_ptr + sizeof(float) * n_view_components * n_texel; |
| |
| /* Retrieve data sampled from the view */ |
| for (unsigned int n_component = 0; n_component < n_view_components; |
| view_texel_data += sizeof(float), /* as per comment */ |
| ++n_component) |
| { |
| switch (view_sampler_type) |
| { |
| case SAMPLER_TYPE_FLOAT: |
| { |
| view_components_float[n_component] = *((float*)view_texel_data); |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_SIGNED_INTEGER: |
| { |
| view_components_int[n_component] = *((signed int*)view_texel_data); |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_UNSIGNED_INTEGER: |
| { |
| view_components_uint[n_component] = *((unsigned int*)view_texel_data); |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized sampler type"); |
| } |
| } /* switch (view_sampler_type) */ |
| } /* for (all components) */ |
| |
| /* Compute reference data. Handle non-byte aligned internalformats manually. */ |
| if (view_internalformat == GL_R11F_G11F_B10F) |
| { |
| const unsigned int* reference_data = (unsigned int*)mipmap_texel_data; |
| const unsigned int red_component = (*reference_data) & ((1 << 11) - 1); |
| const unsigned int green_component = (*reference_data >> 11) & ((1 << 11) - 1); |
| const unsigned int blue_component = (*reference_data >> 22) & ((1 << 10) - 1); |
| |
| if (view_sampler_type == SAMPLER_TYPE_FLOAT) |
| { |
| reference_components_float[0] = Float11(red_component).asFloat(); |
| reference_components_float[1] = Float11(green_component).asFloat(); |
| reference_components_float[2] = Float10(blue_component).asFloat(); |
| } |
| else |
| { |
| TCU_FAIL("Internal error: invalid sampler type requested"); |
| } |
| } |
| else if (view_internalformat == GL_RGB9_E5) |
| { |
| /* Refactored version of tcuTexture.cpp::unpackRGB999E5() */ |
| const unsigned int* reference_data = (unsigned int*)mipmap_texel_data; |
| const unsigned int exponent = (*reference_data >> 27) & ((1 << 5) - 1); |
| const unsigned int red_component = (*reference_data) & ((1 << 9) - 1); |
| const unsigned int green_component = (*reference_data >> 9) & ((1 << 9) - 1); |
| const unsigned int blue_component = (*reference_data >> 18) & ((1 << 9) - 1); |
| |
| float shared_exponent = |
| deFloatPow(2.0f, (float)((int)exponent - 15 /* exponent bias */ - 9 /* mantissa */)); |
| |
| if (view_sampler_type == SAMPLER_TYPE_FLOAT) |
| { |
| reference_components_float[0] = float(red_component) * shared_exponent; |
| reference_components_float[1] = float(green_component) * shared_exponent; |
| reference_components_float[2] = float(blue_component) * shared_exponent; |
| } |
| else |
| { |
| TCU_FAIL("Internal error: invalid sampler type requested"); |
| } |
| } |
| else if (view_internalformat == GL_RGB10_A2) |
| { |
| unsigned int* reference_data = (unsigned int*)mipmap_texel_data; |
| const unsigned int mask_rgb = (1 << 10) - 1; |
| const unsigned int mask_a = (1 << 2) - 1; |
| |
| if (view_sampler_type == SAMPLER_TYPE_FLOAT) |
| { |
| reference_components_float[0] = float(((*reference_data)) & (mask_rgb)) / float(mask_rgb); |
| reference_components_float[1] = float(((*reference_data) >> 10) & (mask_rgb)) / float(mask_rgb); |
| reference_components_float[2] = float(((*reference_data) >> 20) & (mask_rgb)) / float(mask_rgb); |
| reference_components_float[3] = float(((*reference_data) >> 30) & (mask_a)) / float(mask_a); |
| } |
| else |
| { |
| TCU_FAIL("Internal error: invalid sampler type requested"); |
| } |
| } |
| else if (view_internalformat == GL_RGB10_A2UI) |
| { |
| unsigned int* reference_data = (unsigned int*)mipmap_texel_data; |
| const unsigned int mask_rgb = (1 << 10) - 1; |
| const unsigned int mask_a = (1 << 2) - 1; |
| |
| if (view_sampler_type == SAMPLER_TYPE_UNSIGNED_INTEGER) |
| { |
| reference_components_uint[0] = ((*reference_data)) & (mask_rgb); |
| reference_components_uint[1] = ((*reference_data) >> 10) & (mask_rgb); |
| reference_components_uint[2] = ((*reference_data) >> 20) & (mask_rgb); |
| reference_components_uint[3] = ((*reference_data) >> 30) & (mask_a); |
| } |
| else |
| { |
| TCU_FAIL("Internal error: invalid sampler type requested"); |
| } |
| } |
| else if (view_internalformat == GL_RG16F) |
| { |
| unsigned short* reference_data = (unsigned short*)mipmap_texel_data; |
| |
| if (view_sampler_type == SAMPLER_TYPE_FLOAT) |
| { |
| reference_components_float[0] = tcu::Float16(*(reference_data + 0)).asFloat(); |
| reference_components_float[1] = tcu::Float16(*(reference_data + 1)).asFloat(); |
| } |
| else |
| { |
| TCU_FAIL("Internal error: invalid sampler type requested"); |
| } |
| } |
| else |
| { |
| void* result_data = NULL; |
| |
| switch (view_sampler_type) |
| { |
| case SAMPLER_TYPE_FLOAT: |
| result_data = reference_components_float; |
| break; |
| case SAMPLER_TYPE_SIGNED_INTEGER: |
| result_data = reference_components_int; |
| break; |
| case SAMPLER_TYPE_UNSIGNED_INTEGER: |
| result_data = reference_components_uint; |
| break; |
| |
| default: |
| TCU_FAIL("Unrecognized sampler type"); |
| } |
| |
| getComponentDataForByteAlignedInternalformat(mipmap_texel_data, n_view_components, view_component_sizes, |
| view_format, result_data); |
| } |
| |
| for (unsigned int n_component = 0; n_component < n_view_components; ++n_component) |
| { |
| /* If view texture operates on sRGB color space, we need to adjust our |
| * reference value so that it is moved back into linear space. |
| */ |
| if (TextureViewUtilities::isInternalformatSRGB(view_internalformat) && |
| !TextureViewUtilities::isInternalformatSRGB(texture_internalformat)) |
| { |
| DE_ASSERT(view_sampler_type == SAMPLER_TYPE_FLOAT); |
| |
| /* Convert as per (8.14) from GL4.4 spec. Exclude alpha channel. */ |
| if (n_component != 3) |
| { |
| if (reference_components_float[n_component] <= 0.04045f) |
| { |
| reference_components_float[n_component] /= 12.92f; |
| } |
| else |
| { |
| reference_components_float[n_component] = |
| deFloatPow((reference_components_float[n_component] + 0.055f) / 1.055f, 2.4f); |
| } |
| } /* if (n_component != 3) */ |
| } /* if (TextureViewUtilities::isInternalformatSRGB(view_internalformat) ) */ |
| |
| /* Compare the reference and view texture values */ |
| const float epsilon_float = 1.0f / float((1 << (view_component_sizes[n_component] - 1)) - 1); |
| const signed int epsilon_int = 1; |
| const unsigned int epsilon_uint = 1; |
| |
| switch (view_sampler_type) |
| { |
| case SAMPLER_TYPE_FLOAT: |
| { |
| if (de::abs(reference_components_float[n_component] - view_components_float[n_component]) > |
| epsilon_float) |
| { |
| has_failed = true; |
| } |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_SIGNED_INTEGER: |
| { |
| signed int larger_value = 0; |
| signed int smaller_value = 0; |
| |
| if (reference_components_int[n_component] > view_components_int[n_component]) |
| { |
| larger_value = reference_components_int[n_component]; |
| smaller_value = view_components_int[n_component]; |
| } |
| else |
| { |
| smaller_value = reference_components_int[n_component]; |
| larger_value = view_components_int[n_component]; |
| } |
| |
| if ((larger_value - smaller_value) > epsilon_int) |
| { |
| has_failed = true; |
| } |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_UNSIGNED_INTEGER: |
| { |
| unsigned int larger_value = 0; |
| unsigned int smaller_value = 0; |
| |
| if (reference_components_uint[n_component] > view_components_uint[n_component]) |
| { |
| larger_value = reference_components_uint[n_component]; |
| smaller_value = view_components_uint[n_component]; |
| } |
| else |
| { |
| smaller_value = reference_components_uint[n_component]; |
| larger_value = view_components_uint[n_component]; |
| } |
| |
| if ((larger_value - smaller_value) > epsilon_uint) |
| { |
| has_failed = true; |
| } |
| |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized sampler type"); |
| } /* switch (view_sampler_type) */ |
| |
| if (has_failed) |
| { |
| can_continue = false; |
| |
| switch (view_sampler_type) |
| { |
| case SAMPLER_TYPE_FLOAT: |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data sampled from a texture view " |
| "[" |
| << view_internalformat_string << "]" |
| " created from a texture object" |
| "[" |
| << texture_internalformat_string << "]" |
| " at texel " |
| "(" |
| << (n_texel % m_texture_width) << ", " << (n_texel / m_texture_height) |
| << "): expected:(" << reference_components_float[0] << ", " |
| << reference_components_float[1] << ", " << reference_components_float[2] |
| << ", " << reference_components_float[3] << ") found:(" |
| << view_components_float[0] << ", " << view_components_float[1] << ", " |
| << view_components_float[2] << ", " << view_components_float[3] << ")." |
| << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_SIGNED_INTEGER: |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message << "Invalid data sampled from a signed integer texture view " |
| "[" |
| << view_internalformat_string << "]" |
| " created from a texture object" |
| "[" |
| << texture_internalformat_string << "]" |
| " at texel " |
| "(" |
| << (n_texel % m_texture_width) << ", " << (n_texel / m_texture_height) << "): expected:(" |
| << reference_components_int[0] << ", " << reference_components_int[1] << ", " |
| << reference_components_int[2] << ", " << reference_components_int[3] << ") found:(" |
| << view_components_int[0] << ", " << view_components_int[1] << ", " |
| << view_components_int[2] << ", " << view_components_int[3] << ")." |
| << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| case SAMPLER_TYPE_UNSIGNED_INTEGER: |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message << "Invalid data sampled from an unsigned integer texture view " |
| "[" |
| << view_internalformat_string << "]" |
| " created from a texture object" |
| "[" |
| << texture_internalformat_string << "]" |
| " at texel " |
| "(" |
| << (n_texel % m_texture_width) << ", " << (n_texel / m_texture_height) << "): expected:(" |
| << reference_components_uint[0] << ", " << reference_components_uint[1] << ", " |
| << reference_components_uint[2] << ", " << reference_components_uint[3] << ") found:(" |
| << view_components_uint[0] << ", " << view_components_uint[1] << ", " |
| << view_components_uint[2] << ", " << view_components_uint[3] << ")." |
| << tcu::TestLog::EndMessage; |
| |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized sampler type"); |
| } /* switch (view_sampler_type) */ |
| |
| break; |
| } /* if (has_failed) */ |
| } /* for (all components) */ |
| } /* for (all texels) */ |
| } /* if (memcmp(texture_data_ptr, view_data_ptr, m_view_data_offset) != 0) */ |
| |
| if (has_failed) |
| { |
| /* Log detailed information about the failure */ |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data read from a view of internalformat " |
| << "[" << view_internalformat_string << "]" |
| << " created from a texture of internalformat " |
| << "[" << texture_internalformat_string << "]" |
| << ". Byte streams follow:" << tcu::TestLog::EndMessage; |
| |
| /* Form texture and view data strings */ |
| std::stringstream mipmap_data_sstream; |
| std::stringstream sampled_view_data_sstream; |
| |
| mipmap_data_sstream.fill('0'); |
| sampled_view_data_sstream.fill('0'); |
| |
| mipmap_data_sstream.width(2); |
| sampled_view_data_sstream.width(2); |
| |
| mipmap_data_sstream << "Mip-map data: ["; |
| sampled_view_data_sstream << "Sampled view data: ["; |
| |
| for (unsigned int n = 0; n < m_view_data_offset; ++n) |
| { |
| mipmap_data_sstream << "0x" << std::hex << (int)(mipmap_data[n]); |
| sampled_view_data_sstream << "0x" << std::hex << (int)(view_data_ptr[n]); |
| |
| if (n != (m_view_data_offset - 1)) |
| { |
| mipmap_data_sstream << "|"; |
| sampled_view_data_sstream << "|"; |
| } |
| else |
| { |
| mipmap_data_sstream << "]"; |
| sampled_view_data_sstream << "]"; |
| } |
| } |
| |
| sampled_view_data_sstream << "\n"; |
| mipmap_data_sstream << "\n"; |
| |
| /* Log both strings */ |
| m_testCtx.getLog() << tcu::TestLog::Message << mipmap_data_sstream.str() << sampled_view_data_sstream.str() |
| << tcu::TestLog::EndMessage; |
| |
| /* Do not fail the test at this point. Instead, raise a failure flag that will |
| * cause the test to fail once all iterations execute */ |
| m_has_test_failed = true; |
| } |
| else |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Correct data read from a view of internalformat " |
| << "[" << view_internalformat_string << "]" |
| << " created from a texture of internalformat " |
| << "[" << texture_internalformat_string << "]" << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| * |
| **/ |
| TextureViewTestCoherency::TextureViewTestCoherency(deqp::Context& context) |
| : TestCase(context, "coherency", "Verifies view/parent texture coherency") |
| , m_are_images_supported(false) |
| , m_bo_id(0) |
| , m_draw_fbo_id(0) |
| , m_gradient_verification_po_id(0) |
| , m_gradient_verification_po_sample_exact_uv_location(-1) |
| , m_gradient_verification_po_lod_location(-1) |
| , m_gradient_verification_po_texture_location(-1) |
| , m_gradient_verification_vs_id(0) |
| , m_gradient_image_write_image_size_location(-1) |
| , m_gradient_image_write_po_id(0) |
| , m_gradient_image_write_vs_id(0) |
| , m_gradient_write_po_id(0) |
| , m_gradient_write_fs_id(0) |
| , m_gradient_write_vs_id(0) |
| , m_read_fbo_id(0) |
| , m_static_to_id(0) |
| , m_to_id(0) |
| , m_vao_id(0) |
| , m_view_to_id(0) |
| , m_verification_po_expected_color_location(-1) |
| , m_verification_po_lod_location(-1) |
| , m_verification_po_id(0) |
| , m_verification_vs_id(0) |
| , m_static_texture_height(1) |
| , m_static_texture_width(1) |
| , m_texture_height(64) |
| , m_texture_n_components(4) |
| , m_texture_n_levels(7) |
| , m_texture_width(64) |
| { |
| /* Initialize static color that will be used for some of the cases */ |
| m_static_color_byte[0] = 100; |
| m_static_color_byte[1] = 0; |
| m_static_color_byte[2] = 255; |
| m_static_color_byte[3] = 200; |
| |
| m_static_color_float[0] = float(m_static_color_byte[0]) / 255.0f; |
| m_static_color_float[1] = float(m_static_color_byte[1]) / 255.0f; |
| m_static_color_float[2] = float(m_static_color_byte[2]) / 255.0f; |
| m_static_color_float[3] = float(m_static_color_byte[3]) / 255.0f; |
| } |
| |
| /** Verifies that texture/view & view/texture coherency requirement is met |
| * when glTexSubImage2D() or glBlitFramebuffer() API calls are used to modify |
| * the contents of one of the mip-maps. The function does not use any memory |
| * barriers as these are not required for the objects to stay synchronised. |
| * |
| * Throws TestError exceptionif the GL implementation fails the check. |
| * |
| * @param texture_type Defines whether it should be parent texture or |
| * its view that the writing operation should be |
| * performed against. The reading operation will |
| * be issued against the sibling object. |
| * @param should_use_glTexSubImage2D true if glTexSubImage2D() should be used for the |
| * check, false to use glBlitFramebuffer(). |
| * |
| **/ |
| void TextureViewTestCoherency::checkAPICallCoherency(_texture_type texture_type, bool should_use_glTexSubImage2D) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| unsigned int write_to_height = 0; |
| unsigned int write_to_width = 0; |
| glw::GLuint write_to_id = 0; |
| |
| getWritePropertiesForTextureType(texture_type, &write_to_id, &write_to_width, &write_to_height); |
| |
| if (should_use_glTexSubImage2D) |
| { |
| /* Update texture binding for texture unit 0, given the texture type the caller wants |
| * us to test. We'll need the binding set appropriately for the subsequent |
| * glTexSubImage2D() call. |
| */ |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, write_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| } |
| else |
| { |
| /* To perform a blit operation, we need to configure draw & read FBO, taking |
| * the tested texture type into account. */ |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_draw_fbo_id); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call(s) failed."); |
| |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, write_to_id, 1); /* level */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed for GL_DRAW_FRAMEBUFFER target."); |
| |
| gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_static_to_id, |
| 0); /* level */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed for GL_READ_FRAMEBUFFER target."); |
| } |
| |
| /* Execute the API call */ |
| const unsigned int region_width = (write_to_width >> 1); |
| const unsigned int region_height = (write_to_height >> 1); |
| const unsigned int region_x = region_width - (region_width >> 1); |
| const unsigned int region_y = region_height - (region_height >> 1); |
| |
| if (should_use_glTexSubImage2D) |
| { |
| /* Call glTexSubImage2D() to replace a portion of the gradient with a static color */ |
| { |
| unsigned char* static_color_data_ptr = getStaticColorTextureData(region_width, region_height); |
| |
| gl.texSubImage2D(GL_TEXTURE_2D, 1, /* level */ |
| region_x, region_y, region_width, region_height, GL_RGBA, GL_UNSIGNED_BYTE, |
| static_color_data_ptr); |
| |
| /* Good to release static color data buffer at this point */ |
| delete[] static_color_data_ptr; |
| |
| static_color_data_ptr = DE_NULL; |
| |
| /* Make sure the API call was successful */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed."); |
| } |
| } |
| else |
| { |
| gl.blitFramebuffer(0, /* srcX0 */ |
| 0, /* srcY0 */ |
| m_static_texture_width, /* srcX1 */ |
| m_static_texture_height, /* srcY1 */ |
| region_x, region_y, region_x + region_width, region_y + region_height, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBlitFramebuffer() call failed."); |
| } |
| |
| /* Bind the sibling object so that we can make sure the data read from the |
| * region can be correctly read from a shader without a memory barrier. |
| * |
| * While we're here, also determine which LOD we should be sampling from in |
| * the shader. |
| **/ |
| unsigned int read_lod = 0; |
| glw::GLuint read_to_id = 0; |
| |
| getReadPropertiesForTextureType(texture_type, &read_to_id, &read_lod); |
| |
| gl.bindTexture(GL_TEXTURE_2D, read_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Update the test program uniforms before we carry on with actual |
| * verification |
| */ |
| gl.useProgram(m_verification_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| DE_STATIC_ASSERT(sizeof(m_static_color_float) == sizeof(float) * 4); |
| |
| gl.uniform4fv(m_verification_po_expected_color_location, 1, /* count */ |
| m_static_color_float); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed."); |
| |
| gl.uniform1i(m_verification_po_lod_location, read_lod); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| |
| /* Make sure rasterization is disabled before we carry on */ |
| gl.enable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call failed."); |
| |
| /* Go ahead with the rendering. Make sure to capture the varyings */ |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); |
| { |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); |
| |
| /* Map the buffer object so we can validate the sampling result */ |
| const glw::GLint* data_ptr = (const glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed."); |
| DE_ASSERT(data_ptr != NULL); |
| |
| /* Verify the outcome of the sampling operation */ |
| if (*data_ptr != 1) |
| { |
| TCU_FAIL("Invalid data was sampled in vertex shader"); |
| } |
| |
| /* Unmap the buffer object */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); |
| |
| data_ptr = DE_NULL; |
| |
| /* Disable GL_RASTERIZER_DISCARD mode */ |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed."); |
| } |
| |
| /** Verifies texture/view & view/texture coherency is met when one of the objects |
| * is used as a render-target. The function writes to user-specified texture type, |
| * and then verifies the contents of the sibling object. |
| * |
| * The function throws TestError exception if any of the checks fail. |
| * |
| * @param texture_type Tells which of the two objects should be written to. |
| * @param should_use_images true if images should be used for |
| * @param barrier_type Type of the memory barrier that should be injected |
| * after vertex shader stage with image writes is executed. |
| * Must be BARRIER_TYPE_NONE if @param should_use_images |
| * is set to false. |
| * @param verification_mean Determines whether the verification should be performed |
| * using a program object, or by CPU with the data |
| * extracted from the sibling object using a glGetTexImage() |
| * call. |
| * |
| **/ |
| void TextureViewTestCoherency::checkProgramWriteCoherency(_texture_type texture_type, bool should_use_images, |
| _barrier_type barrier_type, |
| _verification_mean verification_mean) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (!should_use_images) |
| { |
| /* Sanity check: no barrier should be requested if images are not used */ |
| DE_ASSERT(barrier_type == BARRIER_TYPE_NONE); |
| |
| /* Sanity check: glGetTexImage*() call should only be used for verification |
| * when images are used */ |
| DE_ASSERT(verification_mean == VERIFICATION_MEAN_PROGRAM); |
| } |
| |
| /* Determine GL id of an object we will be rendering the gradient to */ |
| glw::GLuint write_to_id = 0; |
| unsigned int write_to_width = 0; |
| unsigned int write_to_height = 0; |
| |
| getWritePropertiesForTextureType(texture_type, &write_to_id, &write_to_width, &write_to_height); |
| |
| /* Configure the render targets */ |
| if (should_use_images) |
| { |
| gl.bindImageTexture(0, /* unit */ |
| write_to_id, 1, /* second level */ |
| GL_FALSE, /* layered */ |
| 0, /* layer */ |
| GL_WRITE_ONLY, GL_RGBA8); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed."); |
| } |
| else |
| { |
| /* We first need to fill either the texture or its sibling view with |
| * gradient data. Set up draw framebuffer */ |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_draw_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed for GL_FRAMEBUFFER target"); |
| |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, write_to_id, 1); /* level */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); |
| |
| /* Configure the viewport accordingly */ |
| gl.viewport(0, /* x */ |
| 0, /* y */ |
| write_to_width, write_to_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed."); |
| } |
| |
| /* The gradient needs to be rendered differently, depending on whether |
| * we're asked to use images or not */ |
| if (should_use_images) |
| { |
| gl.useProgram(m_gradient_image_write_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| gl.uniform2i(m_gradient_image_write_image_size_location, write_to_width, write_to_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2i() call failed."); |
| |
| gl.enable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed."); |
| { |
| gl.drawArrays(GL_POINTS, 0 /* first */, write_to_width * write_to_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) call failed."); |
| |
| /* If the caller requested any barriers, issue them at this point */ |
| switch (barrier_type) |
| { |
| case BARRIER_TYPE_TEXTURE_FETCH_BARRIER_BIT: |
| { |
| gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| "glMemoryBarrier() call failed for GL_TEXTURE_FETCH_BARRIER_BIT barrier"); |
| |
| break; |
| } |
| |
| case BARRIER_TYPE_TEXTURE_UPDATE_BUFFER_BIT: |
| { |
| gl.memoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), |
| "glMemoryBarrier() call failed for GL_TEXTURE_UPDATE_BARRIER_BIT barrier"); |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized barrier type"); |
| } |
| } /* switch (barrier_type) */ |
| } /* if (should_use_images) */ |
| else |
| { |
| /* Render the gradient on a full-screen quad */ |
| gl.useProgram(m_gradient_write_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "gluseProgram() call failed."); |
| |
| gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| |
| gl.textureBarrier(); |
| } |
| |
| /* Determine which texture and which mip-map level we will need to sample |
| * in order to verify whether the former operations have been completed |
| * successfully. |
| **/ |
| unsigned int read_lod = 0; |
| glw::GLuint read_to_id = 0; |
| |
| getReadPropertiesForTextureType(texture_type, &read_to_id, &read_lod); |
| |
| /* Before we proceed with verification, update the texture binding so that |
| * the verification program can sample from the right texture */ |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed."); |
| |
| gl.bindTexture(GL_TEXTURE_2D, read_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| if (verification_mean == VERIFICATION_MEAN_PROGRAM) |
| { |
| /* Switch to a verification program. It uses a vertex shader to sample |
| * all texels of the texture so issue as many invocations as necessary. */ |
| unsigned int n_invocations = write_to_width * write_to_height; |
| |
| gl.useProgram(m_gradient_verification_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| gl.uniform1i(m_gradient_verification_po_texture_location, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| |
| gl.uniform1i(m_gradient_verification_po_sample_exact_uv_location, should_use_images); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| |
| gl.uniform1f(m_gradient_verification_po_lod_location, (float)read_lod); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1f() call failed."); |
| |
| gl.enable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed."); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); |
| { |
| gl.drawArrays(GL_POINTS, 0 /* first */, n_invocations); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) call failed."); |
| |
| /* Map the result buffer object storage into process space */ |
| const int* result_data_ptr = (const int*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed."); |
| |
| if (result_data_ptr == DE_NULL) |
| { |
| TCU_FAIL("glMapBuffer() did not generate an error but returned a NULL pointer"); |
| } |
| |
| /* Verify the XFBed data */ |
| for (unsigned int n_invocation = 0; n_invocation < n_invocations; ++n_invocation) |
| { |
| if (result_data_ptr[n_invocation] != 1) |
| { |
| unsigned int invocation_x = n_invocation % write_to_width; |
| unsigned int invocation_y = n_invocation / write_to_width; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data was sampled at " |
| << "(" << invocation_x << ", " << invocation_y << ") when sampling from " |
| << ((texture_type == TEXTURE_TYPE_PARENT_TEXTURE) ? "a texture" : "a view") |
| << tcu::TestLog::EndMessage; |
| |
| /* Make sure the buffer is unmapped before throwing the exception */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| |
| TCU_FAIL("Invalid data sampled"); |
| } |
| } /* for (all invocations) */ |
| |
| /* Unmap the buffer storage */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); |
| } /* if (verification_mean == VERIFICATION_MEAN_PROGRAM) */ |
| else |
| { |
| DE_ASSERT(verification_mean == VERIFICATION_MEAN_GLGETTEXIMAGE); |
| |
| /* Allocate space for the data */ |
| unsigned char* data_ptr = new unsigned char[write_to_width * write_to_height * m_texture_n_components]; |
| |
| /* Retrieve the rendered data */ |
| gl.getTexImage(GL_TEXTURE_2D, read_lod, GL_RGBA, GL_UNSIGNED_BYTE, data_ptr); |
| |
| if (gl.getError() != GL_NO_ERROR) |
| { |
| /* Release the buffer before we throw an exception */ |
| delete[] data_ptr; |
| |
| TCU_FAIL("glGetTexImage() call failed."); |
| } |
| |
| /* Verify the data is correct */ |
| const int epsilon = 1; |
| bool is_data_correct = true; |
| |
| for (unsigned int y = 0; y < write_to_height; ++y) |
| { |
| const unsigned char* row_ptr = data_ptr + y * m_texture_n_components * write_to_width; |
| |
| for (unsigned int x = 0; x < write_to_width; ++x) |
| { |
| const unsigned char* texel_ptr = row_ptr + x * m_texture_n_components; |
| const float end_rgba[] = { 0.0f, 0.1f, 1.0f, 1.0f }; |
| const float lerp_factor = float(x) / float(write_to_width); |
| const float start_rgba[] = { 1.0f, 0.9f, 0.0f, 0.0f }; |
| const float expected_data_float[] = { start_rgba[0] * (1.0f - lerp_factor) + end_rgba[0] * lerp_factor, |
| start_rgba[1] * (1.0f - lerp_factor) + end_rgba[1] * lerp_factor, |
| start_rgba[2] * (1.0f - lerp_factor) + end_rgba[2] * lerp_factor, |
| start_rgba[3] * (1.0f - lerp_factor) + |
| end_rgba[3] * lerp_factor }; |
| const unsigned char expected_data_ubyte[] = { (unsigned char)(expected_data_float[0] * 255.0f), |
| (unsigned char)(expected_data_float[1] * 255.0f), |
| (unsigned char)(expected_data_float[2] * 255.0f), |
| (unsigned char)(expected_data_float[3] * 255.0f) }; |
| |
| if (de::abs((int)texel_ptr[0] - (int)expected_data_ubyte[0]) > epsilon || |
| de::abs((int)texel_ptr[1] - (int)expected_data_ubyte[1]) > epsilon || |
| de::abs((int)texel_ptr[2] - (int)expected_data_ubyte[2]) > epsilon || |
| de::abs((int)texel_ptr[3] - (int)expected_data_ubyte[3]) > epsilon) |
| { |
| is_data_correct = false; |
| |
| break; |
| } |
| } |
| } /* for (all rows) */ |
| |
| /* Good to release the data buffer at this point */ |
| delete[] data_ptr; |
| |
| data_ptr = DE_NULL; |
| |
| /* Fail the test if any of the rendered texels were found invalid */ |
| if (!is_data_correct) |
| { |
| TCU_FAIL("Invalid data sampled"); |
| } |
| } |
| } |
| |
| /** Deinitializes all GL objects that may have been created during |
| * test execution. |
| **/ |
| void TextureViewTestCoherency::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Release any GL objects the test may have created */ |
| if (m_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id); |
| |
| m_bo_id = 0; |
| } |
| |
| if (m_draw_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_draw_fbo_id); |
| |
| m_draw_fbo_id = 0; |
| } |
| |
| if (m_gradient_image_write_po_id != 0) |
| { |
| gl.deleteProgram(m_gradient_image_write_po_id); |
| |
| m_gradient_image_write_po_id = 0; |
| } |
| |
| if (m_gradient_image_write_vs_id != 0) |
| { |
| gl.deleteShader(m_gradient_image_write_vs_id); |
| |
| m_gradient_image_write_vs_id = 0; |
| } |
| |
| if (m_gradient_verification_po_id != 0) |
| { |
| gl.deleteProgram(m_gradient_verification_po_id); |
| |
| m_gradient_verification_po_id = 0; |
| } |
| |
| if (m_gradient_verification_vs_id != 0) |
| { |
| gl.deleteShader(m_gradient_verification_vs_id); |
| |
| m_gradient_verification_vs_id = 0; |
| } |
| |
| if (m_gradient_write_fs_id != 0) |
| { |
| gl.deleteShader(m_gradient_write_fs_id); |
| |
| m_gradient_write_fs_id = 0; |
| } |
| |
| if (m_gradient_write_po_id != 0) |
| { |
| gl.deleteProgram(m_gradient_write_po_id); |
| |
| m_gradient_write_po_id = 0; |
| } |
| |
| if (m_gradient_write_vs_id != 0) |
| { |
| gl.deleteShader(m_gradient_write_vs_id); |
| |
| m_gradient_write_vs_id = 0; |
| } |
| |
| if (m_read_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_read_fbo_id); |
| |
| m_read_fbo_id = 0; |
| } |
| |
| if (m_static_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_static_to_id); |
| |
| m_static_to_id = 0; |
| } |
| |
| if (m_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| |
| m_to_id = 0; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| |
| if (m_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_to_id); |
| |
| m_view_to_id = 0; |
| } |
| |
| if (m_verification_po_id != 0) |
| { |
| gl.deleteProgram(m_verification_po_id); |
| |
| m_verification_po_id = 0; |
| } |
| |
| if (m_verification_vs_id != 0) |
| { |
| gl.deleteShader(m_verification_vs_id); |
| |
| m_verification_vs_id = 0; |
| } |
| |
| /* Disable GL_RASTERIZER_DISCARD mode */ |
| gl.disable(GL_RASTERIZER_DISCARD); |
| } |
| |
| /** Allocates a sufficiently large buffer for RGBA8 data and fills it with |
| * a horizontal gradient (as described in the test specification) |
| * |
| * It is user's responsibility to release the buffer when no longer needed. |
| * |
| * @return Pointer to the buffer. |
| **/ |
| unsigned char* TextureViewTestCoherency::getHorizontalGradientData() const |
| { |
| const float end_rgba[] = { 1.0f, 0.9f, 0.0f, 0.0f }; |
| unsigned char* result = new unsigned char[m_texture_width * m_texture_height * m_texture_n_components]; |
| const float start_rgba[] = { 0.0f, 0.1f, 1.0f, 1.0f }; |
| const unsigned int texel_size = m_texture_n_components; |
| |
| for (unsigned int y = 0; y < m_texture_height; ++y) |
| { |
| unsigned char* row_data_ptr = result + texel_size * m_texture_width * y; |
| |
| for (unsigned int x = 0; x < m_texture_width; ++x) |
| { |
| const float lerp_factor = float(x) / float(m_texture_width); |
| unsigned char* pixel_data_ptr = row_data_ptr + texel_size * x; |
| |
| for (unsigned int n_component = 0; n_component < 4 /* rgba */; ++n_component) |
| { |
| pixel_data_ptr[n_component] = (unsigned char)((end_rgba[n_component] * lerp_factor + |
| start_rgba[n_component] * (1.0f - lerp_factor)) * |
| 255.0f); |
| } /* for (all components) */ |
| } /* for (all columns) */ |
| } /* for (all rows) */ |
| |
| return result; |
| } |
| |
| /** Retrieves properties of a sibling object that should be read from during |
| * some of the checks. |
| * |
| * @param texture_type Type of the texture object that should be used for reading. |
| * @param out_to_id Deref will be used to store texture object ID of the object. |
| * @param out_read_lod Deref will be used to store LOD to be used for reading from |
| * the object. |
| * |
| **/ |
| void TextureViewTestCoherency::getReadPropertiesForTextureType(_texture_type texture_type, glw::GLuint* out_to_id, |
| unsigned int* out_read_lod) const |
| { |
| switch (texture_type) |
| { |
| case TEXTURE_TYPE_PARENT_TEXTURE: |
| { |
| *out_to_id = m_view_to_id; |
| |
| /* We've modified LOD1 of parent texture which corresponds |
| * to LOD 0 from the view's PoV |
| */ |
| *out_read_lod = 0; |
| |
| break; |
| } |
| |
| case TEXTURE_TYPE_TEXTURE_VIEW: |
| { |
| *out_to_id = m_to_id; |
| |
| /* We've modified LOD1 of the view texture which corresponds |
| * to LOD2 from parent texture's PoV. |
| */ |
| *out_read_lod = 2; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized read source"); |
| } |
| } /* switch (texture_type) */ |
| } |
| |
| /** Allocates a sufficiently large buffer to hold RGBA8 data of user-specified resolution |
| * and fills it with a static color (as described in the test specification) |
| * |
| * It is caller's responsibility to release the returned buffer when it's no longer |
| * needed. |
| * |
| * @param width Width of the mip-map the buffer will be used as a data source for; |
| * @param height Height of the mip-map the buffer will be used as a data source for; |
| * |
| * @return Pointer to the buffer. |
| **/ |
| unsigned char* TextureViewTestCoherency::getStaticColorTextureData(unsigned int width, unsigned int height) const |
| { |
| /* Prepare the data buffer storing the data we want to replace the region of the |
| * data source with. |
| */ |
| unsigned char* result_ptr = new unsigned char[width * height * m_texture_n_components]; |
| |
| for (unsigned int y = 0; y < height; ++y) |
| { |
| unsigned char* row_data_ptr = result_ptr + y * width * m_texture_n_components; |
| |
| for (unsigned int x = 0; x < width; ++x) |
| { |
| unsigned char* pixel_data_ptr = row_data_ptr + x * m_texture_n_components; |
| |
| memcpy(pixel_data_ptr, m_static_color_byte, sizeof(m_static_color_byte)); |
| } /* for (all columns) */ |
| } /* for (all rows) */ |
| |
| return result_ptr; |
| } |
| |
| /** Retrieves properties of a parent texture object that should be written to during |
| * some of the checks. |
| * |
| * @param texture_type Type of the texture object that should be used for writing. |
| * @param out_to_id Deref will be used to store texture object ID of the object. Must not be NULL. |
| * @param out_width Deref will be used to store width of the mip-map the test will |
| * be writing to; Must not be NULL. |
| * @param out_height Deref will be used to store height of the mip-map the test will |
| * be writing to. Must not be NULL. |
| * |
| **/ |
| void TextureViewTestCoherency::getWritePropertiesForTextureType(_texture_type texture_type, glw::GLuint* out_to_id, |
| unsigned int* out_width, unsigned int* out_height) const |
| { |
| DE_ASSERT(out_to_id != DE_NULL); |
| DE_ASSERT(out_width != DE_NULL); |
| DE_ASSERT(out_height != DE_NULL); |
| |
| /* All tests will be attempting to modify layer 1 of either the texture |
| * or its sibling view. For views, the resolution is therefore going to |
| * be 16x16 (because the base resolution is 32x32, as the view uses a mipmap |
| * range of 1 to 2 inclusive); for parent texture, this will be 32x32 (as the base |
| * mip-map is 64x64) |
| */ |
| switch (texture_type) |
| { |
| case TEXTURE_TYPE_PARENT_TEXTURE: |
| { |
| *out_to_id = m_to_id; |
| *out_width = m_texture_width >> 1; |
| *out_height = m_texture_height >> 1; |
| |
| break; |
| } |
| |
| case TEXTURE_TYPE_TEXTURE_VIEW: |
| { |
| *out_to_id = m_view_to_id; |
| *out_width = m_texture_width >> 2; |
| *out_height = m_texture_height >> 2; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized texture type"); |
| } |
| } /* switch (texture_type) */ |
| } |
| |
| /** Initializes buffer objects that will be used during the test. |
| * |
| * Throws exceptions if the initialization fails at any point. |
| **/ |
| void TextureViewTestCoherency::initBufferObjects() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate and configure buffer object storage */ |
| gl.genBuffers(1, &m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed."); |
| |
| /* Case 1) needs the BO to hold just a single int. |
| * Case 3) needs one int per result texel. |
| * |
| * Allocate enough space to handle all the cases. |
| **/ |
| glw::GLint bo_size = static_cast<glw::GLint>((m_texture_height >> 1) * (m_texture_width >> 1) * sizeof(int)); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */ |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferdata() call failed."); |
| } |
| |
| /** Initializes framebuffer objects that will be used during the test. |
| * |
| * Throws exceptions if the initialization fails at any point. |
| **/ |
| void TextureViewTestCoherency::initFBO() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate framebuffer object(s) */ |
| gl.genFramebuffers(1, &m_draw_fbo_id); |
| gl.genFramebuffers(1, &m_read_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed."); |
| } |
| |
| /** Initializes program objects that will be used during the test. |
| * |
| * This method will throw exceptions if either compilation or linking of |
| * any of the processed shaders/programs fails. |
| * |
| **/ |
| void TextureViewTestCoherency::initPrograms() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* The test uses images in vertex shader stage. Make sure this is actually supported by |
| * the implementation */ |
| m_are_images_supported = m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_image_load_store"); |
| |
| if (m_are_images_supported) |
| { |
| glw::GLint gl_max_vertex_image_uniforms_value = 0; |
| |
| gl.getIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &gl_max_vertex_image_uniforms_value); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_VERTEX_IMAGE_UNIFORM pname"); |
| |
| if (gl_max_vertex_image_uniforms_value < 1) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Image support will not be tested by view_parent_texture_coherency, as" |
| "the implementation does not support image uniforms in vertex shader stage." |
| << tcu::TestLog::EndMessage; |
| |
| /* We cannot execute the test on this platform */ |
| m_are_images_supported = false; |
| } |
| } /* if (m_are_images_supported) */ |
| |
| /* Create program objects */ |
| if (m_are_images_supported) |
| { |
| m_gradient_image_write_po_id = gl.createProgram(); |
| } |
| |
| m_gradient_verification_po_id = gl.createProgram(); |
| m_gradient_write_po_id = gl.createProgram(); |
| m_verification_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed."); |
| |
| /* Create fragment shader objects */ |
| m_gradient_write_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for GL_FRAGMENT_SHADER type"); |
| |
| /* Create vertex shader objects */ |
| if (m_are_images_supported) |
| { |
| m_gradient_image_write_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| } |
| |
| m_gradient_verification_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| m_gradient_write_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| m_verification_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed for GL_VERTEX_SHADER type."); |
| |
| /* Set gradient verification program's fragment shader body */ |
| const char* gradient_verification_vs_body = |
| "#version 400\n" |
| "\n" |
| "out int result;\n" |
| "\n" |
| "uniform float lod;\n" |
| "uniform bool sample_exact_uv;\n" |
| "uniform sampler2D texture;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float epsilon = 1.0 / 255.0;\n" |
| " const vec4 end_rgba = vec4(0.0, 0.1, 1.0, 1.0);\n" |
| " const vec4 start_rgba = vec4(1.0, 0.9, 0.0, 0.0);\n" |
| "\n" |
| " ivec2 texture_size = textureSize(texture, int(lod) );\n" |
| " vec2 uv = vec2( float(gl_VertexID % texture_size.x) / float(texture_size.x),\n" |
| " 1.0 - float(gl_VertexID / texture_size.x) / float(texture_size.y) );\n" |
| " vec4 expected_color;\n" |
| " vec4 texture_color = textureLod(texture, uv, lod);\n" |
| "\n" |
| " if (sample_exact_uv)\n" |
| " {\n" |
| " expected_color = mix(start_rgba, end_rgba, uv.x);\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " expected_color = mix(start_rgba, end_rgba, uv.x + 0.5/float(texture_size.x) );\n" |
| " }\n" |
| "\n" |
| "\n" |
| " if (abs(texture_color.x - expected_color.x) > epsilon ||\n" |
| " abs(texture_color.y - expected_color.y) > epsilon ||\n" |
| " abs(texture_color.z - expected_color.z) > epsilon ||\n" |
| " abs(texture_color.w - expected_color.w) > epsilon)\n" |
| " {\n" |
| " result = int( texture_color.y * 255.0);\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " result = 1;\n" |
| " }\n" |
| "}\n"; |
| |
| gl.shaderSource(m_gradient_verification_vs_id, 1 /* count */, &gradient_verification_vs_body, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Set gradient write (for images) program's vertex shader body */ |
| if (m_are_images_supported) |
| { |
| const char* gradient_write_image_vs_body = |
| "#version 400\n" |
| "\n" |
| "#extension GL_ARB_shader_image_load_store : require\n" |
| "\n" |
| "layout(rgba8) uniform image2D image;\n" |
| " uniform ivec2 image_size;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const vec4 end_rgba = vec4(0.0, 0.1, 1.0, 1.0);\n" |
| " const vec4 start_rgba = vec4(1.0, 0.9, 0.0, 0.0);\n" |
| " ivec2 xy = ivec2(gl_VertexID % image_size.x, gl_VertexID / image_size.x);\n" |
| " vec2 uv = vec2(float(xy.x) / float(image_size.x), 1.0 - float(xy.y) / " |
| "float(image_size.y) );\n" |
| " vec4 result = mix (start_rgba, end_rgba, uv.x);\n" |
| "\n" |
| " imageStore(image, xy, result);\n" |
| "}\n"; |
| |
| gl.shaderSource(m_gradient_image_write_vs_id, 1 /* count */, &gradient_write_image_vs_body, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| } |
| |
| /* Set gradient write program's fragment shader body */ |
| const char* gradient_write_fs_body = "#version 400\n" |
| "\n" |
| "in vec2 uv;\n" |
| "\n" |
| "layout(location = 0) out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const vec4 end_rgba = vec4(0.0, 0.1, 1.0, 1.0);\n" |
| " const vec4 start_rgba = vec4(1.0, 0.9, 0.0, 0.0);\n" |
| "\n" |
| " result = mix(start_rgba, end_rgba, uv.x);\n" |
| "}\n"; |
| |
| gl.shaderSource(m_gradient_write_fs_id, 1 /* count */, &gradient_write_fs_body, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Set gradient write program's vertex shader body */ |
| const char* gradient_write_vs_body = |
| "#version 400\n" |
| "\n" |
| "out vec2 uv;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " switch (gl_VertexID)\n" |
| " {\n" |
| " case 0: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); uv = vec2(0.0, 1.0); break;\n" |
| " case 1: gl_Position = vec4(-1.0, 1.0, 0.0, 1.0); uv = vec2(0.0, 0.0); break;\n" |
| " case 2: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); uv = vec2(1.0, 1.0); break;\n" |
| " case 3: gl_Position = vec4( 1.0, 1.0, 0.0, 1.0); uv = vec2(1.0, 0.0); break;\n" |
| " }\n" |
| "}\n"; |
| |
| gl.shaderSource(m_gradient_write_vs_id, 1 /* count */, &gradient_write_vs_body, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Set verification program's vertex shader body */ |
| const char* verification_vs_body = "#version 400\n" |
| "\n" |
| "uniform vec4 expected_color;\n" |
| "uniform int lod;\n" |
| "uniform sampler2D sampler;\n" |
| "\n" |
| "out int result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float epsilon = 1.0 / 256.0;\n" |
| "\n" |
| " vec4 sampled_data = textureLod(sampler, vec2(0.5, 0.5), lod);\n" |
| "\n" |
| " if (abs(sampled_data.x - expected_color.x) > epsilon ||\n" |
| " abs(sampled_data.y - expected_color.y) > epsilon ||\n" |
| " abs(sampled_data.z - expected_color.z) > epsilon ||\n" |
| " abs(sampled_data.w - expected_color.w) > epsilon)\n" |
| " {\n" |
| " result = 0;\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " result = 1;\n" |
| " }\n" |
| "}\n"; |
| |
| gl.shaderSource(m_verification_vs_id, 1 /* count */, &verification_vs_body, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Compile the shaders */ |
| const glw::GLuint so_ids[] = { m_gradient_image_write_vs_id, m_gradient_verification_vs_id, m_gradient_write_fs_id, |
| m_gradient_write_vs_id, m_verification_vs_id }; |
| const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]); |
| |
| for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id) |
| { |
| glw::GLuint so_id = so_ids[n_so_id]; |
| |
| if (so_id != 0) |
| { |
| gl.compileShader(so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| /* Verify the compilation ended successfully */ |
| glw::GLint compile_status = GL_FALSE; |
| |
| gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| TCU_FAIL("Shader compilation failed."); |
| } |
| } |
| } /* for (all shader objects) */ |
| |
| /* Attach the shaders to relevant programs */ |
| if (m_are_images_supported) |
| { |
| gl.attachShader(m_gradient_image_write_po_id, m_gradient_image_write_vs_id); |
| } |
| |
| gl.attachShader(m_gradient_verification_po_id, m_gradient_verification_vs_id); |
| gl.attachShader(m_gradient_write_po_id, m_gradient_write_fs_id); |
| gl.attachShader(m_gradient_write_po_id, m_gradient_write_vs_id); |
| gl.attachShader(m_verification_po_id, m_verification_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); |
| |
| /* Set up XFB */ |
| const char* verification_varying_name = "result"; |
| const glw::GLuint xfb_po_ids[] = { |
| m_gradient_verification_po_id, m_verification_po_id, |
| }; |
| const unsigned int n_xfb_po_ids = sizeof(xfb_po_ids) / sizeof(xfb_po_ids[0]); |
| |
| for (unsigned int n_xfb_po_id = 0; n_xfb_po_id < n_xfb_po_ids; ++n_xfb_po_id) |
| { |
| glw::GLint po_id = xfb_po_ids[n_xfb_po_id]; |
| |
| gl.transformFeedbackVaryings(po_id, 1 /* count */, &verification_varying_name, GL_INTERLEAVED_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); |
| } |
| |
| /* Link the programs */ |
| const glw::GLuint po_ids[] = { m_gradient_image_write_po_id, m_gradient_verification_po_id, m_gradient_write_po_id, |
| m_verification_po_id }; |
| const unsigned int n_po_ids = sizeof(po_ids) / sizeof(po_ids[0]); |
| |
| for (unsigned int n_po_id = 0; n_po_id < n_po_ids; ++n_po_id) |
| { |
| glw::GLuint po_id = po_ids[n_po_id]; |
| |
| if (po_id != 0) |
| { |
| gl.linkProgram(po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| /* Make sure the linking was successful. */ |
| glw::GLint link_status = GL_FALSE; |
| |
| gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status != GL_TRUE) |
| { |
| TCU_FAIL("Program linking failed."); |
| } |
| } |
| } /* for (all program objects) */ |
| |
| /* Retrieve uniform locations for gradient write program (image case) */ |
| if (m_are_images_supported) |
| { |
| m_gradient_image_write_image_size_location = gl.getUniformLocation(m_gradient_image_write_po_id, "image_size"); |
| |
| if (m_gradient_image_write_image_size_location == -1) |
| { |
| TCU_FAIL("image_size is considered an inactive uniform which is invalid."); |
| } |
| } |
| |
| /* Retrieve uniform locations for gradient verification program */ |
| m_gradient_verification_po_sample_exact_uv_location = |
| gl.getUniformLocation(m_gradient_verification_po_id, "sample_exact_uv"); |
| m_gradient_verification_po_lod_location = gl.getUniformLocation(m_gradient_verification_po_id, "lod"); |
| m_gradient_verification_po_texture_location = gl.getUniformLocation(m_gradient_verification_po_id, "texture"); |
| |
| if (m_gradient_verification_po_sample_exact_uv_location == -1) |
| { |
| TCU_FAIL("sample_exact_uv is considered an inactive uniform which is invalid"); |
| } |
| |
| if (m_gradient_verification_po_lod_location == -1) |
| { |
| TCU_FAIL("lod is considered an inactive uniform which is invalid."); |
| } |
| |
| if (m_gradient_verification_po_texture_location == -1) |
| { |
| TCU_FAIL("texture is considered an inactive uniform which is invalid."); |
| } |
| |
| /* Retrieve uniform locations for verification program */ |
| m_verification_po_expected_color_location = gl.getUniformLocation(m_verification_po_id, "expected_color"); |
| m_verification_po_lod_location = gl.getUniformLocation(m_verification_po_id, "lod"); |
| |
| if (m_verification_po_expected_color_location == -1) |
| { |
| TCU_FAIL("expected_color is considered an inactive uniform which is invalid."); |
| } |
| |
| if (m_verification_po_lod_location == -1) |
| { |
| TCU_FAIL("lod is considered an inactive uniform which is invalid."); |
| } |
| } |
| |
| /** Initializes texture objects required to run the test. |
| * |
| * Throws exceptions if the initialization fails at any point. |
| **/ |
| void TextureViewTestCoherency::initTextures() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate the texture objects */ |
| gl.genTextures(1, &m_static_to_id); |
| gl.genTextures(1, &m_to_id); |
| gl.genTextures(1, &m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed."); |
| |
| /* Set up parent texture object */ |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, m_texture_n_levels, GL_RGBA8, m_texture_width, m_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call(s) failed."); |
| |
| /* Set up the texture views we'll be using for the test */ |
| gl.textureView(m_view_to_id, GL_TEXTURE_2D, m_to_id, GL_RGBA8, 1, /* minlevel */ |
| 2, /* numlevels */ |
| 0, /* minlayer */ |
| 1); /* numlayers */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_view_to_id); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
| |
| /* Set up storage for static color texture */ |
| gl.bindTexture(GL_TEXTURE_2D, m_static_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ |
| GL_RGBA8, m_static_texture_width, m_static_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); |
| |
| /* Fill the texture objects with actual contents */ |
| initTextureContents(); |
| } |
| |
| /** Fills all relevant mip-maps of all previously initialized texture objects with |
| * contents. |
| * |
| * Throws an exception if any of the issued GL API calls fail. |
| **/ |
| void TextureViewTestCoherency::initTextureContents() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Make sure parent texture object is bound before we start modifying |
| * the mip-maps */ |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Set up parent texture mip-maps */ |
| unsigned char* base_mipmap_data_ptr = getHorizontalGradientData(); |
| |
| gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */ |
| 0, /* xoffset */ |
| 0, /* yoffset */ |
| m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, base_mipmap_data_ptr); |
| |
| delete[] base_mipmap_data_ptr; |
| base_mipmap_data_ptr = NULL; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed."); |
| |
| /* Generate all mip-maps */ |
| gl.generateMipmap(GL_TEXTURE_2D); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap() call failed."); |
| |
| /* Set up static color texture contents. We only need to fill the base mip-map |
| * since the texture's resolution is 1x1. |
| */ |
| DE_ASSERT(m_static_texture_height == 1 && m_static_texture_width == 1); |
| |
| unsigned char* static_texture_data_ptr = getStaticColorTextureData(m_static_texture_width, m_static_texture_height); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_static_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */ |
| 0, /* xoffset */ |
| 0, /* yoffset */ |
| m_static_texture_width, m_static_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, |
| static_texture_data_ptr); |
| |
| /* Good to release the buffer at this point */ |
| delete[] static_texture_data_ptr; |
| |
| static_texture_data_ptr = DE_NULL; |
| |
| /* Was the API call successful? */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed."); |
| } |
| |
| /** Initializes a vertex array object used for the draw calls issued during the test. */ |
| void TextureViewTestCoherency::initVAO() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate and bind a vertex array object */ |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); |
| |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestCoherency::iterate() |
| { |
| /* Do not execute the test if GL_ARB_texture_view is not supported */ |
| if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_texture_view")) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported."); |
| } |
| |
| /* Initialize all GL objects required to run the test */ |
| initBufferObjects(); |
| initPrograms(); |
| initTextures(); |
| initFBO(); |
| initVAO(); |
| |
| /* Iterate over the set of texture types we are to test */ |
| const _texture_type texture_types[] = { TEXTURE_TYPE_PARENT_TEXTURE, TEXTURE_TYPE_TEXTURE_VIEW }; |
| const unsigned int n_texture_types = sizeof(texture_types) / sizeof(texture_types[0]); |
| |
| for (unsigned int n_texture_type = 0; n_texture_type < n_texture_types; ++n_texture_type) |
| { |
| _texture_type texture_type = texture_types[n_texture_type]; |
| |
| /* Verify parent texture/view coherency when using glTexSubImage2D() */ |
| checkAPICallCoherency(texture_type, true); |
| |
| /* Verify parent texture/view coherency when using glBlitFramebuffer() */ |
| checkAPICallCoherency(texture_type, false); |
| |
| /* Verify parent texture/view coherency when modifying contents of one |
| * of the objects in a program, and then reading the sibling from another |
| * program. |
| */ |
| checkProgramWriteCoherency(texture_type, false, /* should_use_images */ |
| BARRIER_TYPE_NONE, VERIFICATION_MEAN_PROGRAM); |
| |
| if (m_are_images_supported) |
| { |
| /* Verify a view bound to an image unit and written to using image uniforms |
| * in vertex shader stage can later be sampled correctly, assuming |
| * a GL_TEXTURE_FETCH_BARRIER_BIT barrier is inserted between the write |
| * operations and sampling from another program object. |
| */ |
| checkProgramWriteCoherency(texture_type, true, /* should_use_images */ |
| BARRIER_TYPE_TEXTURE_FETCH_BARRIER_BIT, VERIFICATION_MEAN_PROGRAM); |
| |
| /* Verify a view bound to an image unit and written to using image uniforms |
| * in vertex shader stage can later be correctly retrieved using a glGetTexImage() |
| * call, assuming a GL_TEXTURE_UPDATE_BARRIER_BIT barrier is inserted between the |
| * two operations. |
| **/ |
| checkProgramWriteCoherency(texture_type, true, /* should_use_images */ |
| BARRIER_TYPE_TEXTURE_UPDATE_BUFFER_BIT, VERIFICATION_MEAN_GLGETTEXIMAGE); |
| } |
| |
| /* Reinitialize all texture contents */ |
| initTextureContents(); |
| } /* for (all read sources) */ |
| |
| /* Test case passed */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| * |
| **/ |
| TextureViewTestBaseAndMaxLevels::TextureViewTestBaseAndMaxLevels(deqp::Context& context) |
| : TestCase(context, "base_and_max_levels", "test_description") |
| , m_texture_height(256) |
| , m_texture_n_components(4) |
| , m_texture_n_levels(6) |
| , m_texture_width(256) |
| , m_view_height(128) |
| , m_view_width(128) |
| , m_layer_data_lod0(DE_NULL) |
| , m_layer_data_lod1(DE_NULL) |
| , m_fbo_id(0) |
| , m_fs_id(0) |
| , m_po_id(0) |
| , m_po_lod_index_uniform_location(-1) |
| , m_po_to_sampler_uniform_location(-1) |
| , m_result_to_id(0) |
| , m_to_id(0) |
| , m_vao_id(0) |
| , m_view_to_id(0) |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /* Deinitializes all GL objects that may have been created during test execution. */ |
| void TextureViewTestBaseAndMaxLevels::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| |
| m_fbo_id = 0; |
| } |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| |
| m_fs_id = 0; |
| } |
| |
| if (m_layer_data_lod0 != DE_NULL) |
| { |
| delete[] m_layer_data_lod0; |
| |
| m_layer_data_lod0 = DE_NULL; |
| } |
| |
| if (m_layer_data_lod1 != DE_NULL) |
| { |
| delete[] m_layer_data_lod1; |
| |
| m_layer_data_lod1 = DE_NULL; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| |
| if (m_result_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_result_to_id); |
| |
| m_result_to_id = 0; |
| } |
| |
| if (m_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| |
| m_to_id = 0; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| |
| if (m_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_to_id); |
| |
| m_view_to_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /* Initializes and configures a program object used later by the test. */ |
| void TextureViewTestBaseAndMaxLevels::initProgram() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate shader object IDs */ |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed"); |
| |
| /* Generate program object ID */ |
| m_po_id = gl.createProgram(); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed"); |
| |
| /* Set up vertex shader body */ |
| static const char* vs_body = |
| "#version 400\n" |
| "\n" |
| "out vec2 uv;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " switch (gl_VertexID)\n" |
| " {\n" |
| " case 0: gl_Position = vec4(-1.0, 1.0, 0.0, 1.0); uv = vec2(0.0, 1.0); break;\n" |
| " case 1: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); uv = vec2(0.0, 0.0); break;\n" |
| " case 2: gl_Position = vec4( 1.0, 1.0, 0.0, 1.0); uv = vec2(1.0, 1.0); break;\n" |
| " case 3: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); uv = vec2(1.0, 0.0); break;\n" |
| " };\n" |
| "}\n"; |
| |
| gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for vertex shader case"); |
| |
| /* Set up fragment shader body */ |
| static const char* fs_body = "#version 400\n" |
| "\n" |
| "in vec2 uv;\n" |
| "\n" |
| "uniform int lod_index;\n" |
| "uniform sampler2D to_sampler;\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = textureLod(to_sampler, uv, float(lod_index) );\n" |
| "}\n"; |
| |
| gl.shaderSource(m_fs_id, 1 /* count */, &fs_body, DE_NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for fragment shader case"); |
| |
| /* Compile both shaders */ |
| const glw::GLuint so_ids[] = { m_fs_id, m_vs_id }; |
| const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]); |
| |
| for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id) |
| { |
| glw::GLint so_id = so_ids[n_so_id]; |
| |
| gl.compileShader(so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| /* Make sure the compilation has succeeded */ |
| glw::GLint compile_status = GL_FALSE; |
| |
| gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed" << tcu::TestLog::EndMessage; |
| } |
| } /* for (all shader objects) */ |
| |
| /* Attach the shaders to the program object */ |
| gl.attachShader(m_po_id, m_fs_id); |
| gl.attachShader(m_po_id, m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed"); |
| |
| /* Link the program object */ |
| gl.linkProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call faikled"); |
| |
| /* Verify the linking has succeeded */ |
| glw::GLint link_status = GL_FALSE; |
| |
| gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_LINK_STATUS pname"); |
| |
| if (link_status != GL_TRUE) |
| { |
| TCU_FAIL("Program linking failed"); |
| } |
| |
| /* Retrieve uniform locations */ |
| m_po_lod_index_uniform_location = gl.getUniformLocation(m_po_id, "lod_index"); |
| m_po_to_sampler_uniform_location = gl.getUniformLocation(m_po_id, "to_sampler"); |
| |
| if (m_po_lod_index_uniform_location == -1) |
| { |
| TCU_FAIL("lod_index is considered an inactive uniform"); |
| } |
| |
| if (m_po_to_sampler_uniform_location == -1) |
| { |
| TCU_FAIL("to_sampler is considered an inactive uniform"); |
| } |
| } |
| |
| /* Initializes all GL objects used by the test. */ |
| void TextureViewTestBaseAndMaxLevels::initTest() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Initialize textures */ |
| initTextures(); |
| |
| /* Initialize framebuffer and configure its attachments */ |
| gl.genFramebuffers(1, &m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed"); |
| |
| /* Build the program we'll need for the test */ |
| initProgram(); |
| |
| /* Generate a vertex array object to execute the draw calls */ |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); |
| |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); |
| |
| /* Finally, allocate space for buffers that will be filled with rendered data */ |
| m_layer_data_lod0 = new unsigned char[m_texture_width * m_texture_height * m_texture_n_components]; |
| m_layer_data_lod1 = new unsigned char[(m_texture_width >> 1) * (m_texture_height >> 1) * m_texture_n_components]; |
| |
| if (m_layer_data_lod0 == DE_NULL || m_layer_data_lod1 == DE_NULL) |
| { |
| TCU_FAIL("Out of memory"); |
| } |
| } |
| |
| /** Initializes texture objects used by the test. */ |
| void TextureViewTestBaseAndMaxLevels::initTextures() |
| { |
| /* Generate IDs first */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.genTextures(1, &m_result_to_id); |
| gl.genTextures(1, &m_to_id); |
| gl.genTextures(1, &m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed"); |
| |
| /* Set up parent texture object's storage */ |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, m_texture_n_levels, GL_RGBA8, m_texture_width, m_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| |
| /* Configure GL_TEXTURE_BASE_LEVEL parameter of the texture object as per test spec */ |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call failed for GL_TEXTURE_BASE_LEVEL pname"); |
| |
| /* Configure GL_TEXTURE_MAX_LEVEL parameter of the texture object as per test spec */ |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call failed for GL_TEXTURE_MAX_LEVEL pname"); |
| |
| /* Set up mip-maps */ |
| for (unsigned int n_mipmap = 0; n_mipmap < m_texture_n_levels; ++n_mipmap) |
| { |
| const float start_rgba[] = { /* As per test specification */ |
| float(n_mipmap + 0) / 10.0f, float(n_mipmap + 1) / 10.0f, |
| float(n_mipmap + 2) / 10.0f, float(n_mipmap + 3) / 10.0f |
| }; |
| const float end_rgba[] = { float(10 - (n_mipmap + 0)) / 10.0f, float(10 - (n_mipmap + 1)) / 10.0f, |
| float(10 - (n_mipmap + 2)) / 10.0f, float(10 - (n_mipmap + 3)) / 10.0f }; |
| |
| /* Allocate space for the layer data */ |
| const unsigned int mipmap_height = m_texture_height >> n_mipmap; |
| const unsigned int mipmap_width = m_texture_width >> n_mipmap; |
| unsigned char* data = new unsigned char[mipmap_width * mipmap_height * m_texture_n_components]; |
| |
| if (data == NULL) |
| { |
| TCU_FAIL("Out of memory"); |
| } |
| |
| /* Fill the buffer with layer data */ |
| const unsigned int pixel_size = 4 /* components */; |
| |
| for (unsigned int y = 0; y < mipmap_height; ++y) |
| { |
| unsigned char* row_data_ptr = data + mipmap_width * y * pixel_size; |
| |
| for (unsigned int x = 0; x < mipmap_width; ++x) |
| { |
| const float lerp_factor = float(x) / float(mipmap_width); |
| unsigned char* pixel_data_ptr = row_data_ptr + x * pixel_size; |
| |
| for (unsigned int n_component = 0; n_component < m_texture_n_components; n_component++) |
| { |
| pixel_data_ptr[n_component] = (unsigned char)((start_rgba[n_component] * lerp_factor + |
| end_rgba[n_component] * (1.0f - lerp_factor)) * |
| 255.0f); |
| } |
| } /* for (all columns) */ |
| } /* for (all rows) */ |
| |
| /* Upload the layer data */ |
| gl.texSubImage2D(GL_TEXTURE_2D, n_mipmap, 0, /* xoffset */ |
| 0, /* yoffset */ |
| mipmap_width, mipmap_height, GL_RGBA, GL_UNSIGNED_BYTE, data); |
| |
| /* Release the data buffer */ |
| delete[] data; |
| |
| data = DE_NULL; |
| |
| /* Make sure the API call finished successfully */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed"); |
| } /* for (all mip-maps) */ |
| |
| /* Configure the texture view storage as per spec. */ |
| gl.textureView(m_view_to_id, GL_TEXTURE_2D, m_to_id, GL_RGBA8, 0, /* minlevel */ |
| 5, /* numlevels */ |
| 0, /* minlayer */ |
| 1); /* numlayers */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed"); |
| |
| /* Configure the texture view's GL_TEXTURE_BASE_LEVEL parameter */ |
| gl.bindTexture(GL_TEXTURE_2D, m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call failed for GL_TEXTURE_BASE_LEVEL pname"); |
| |
| /* Configure the texture view's GL_TEXTURE_MAX_LEVEL parameter */ |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() call failed for GL_TEXTURE_MAX_LEVEL pname"); |
| |
| /* Set up result texture storage */ |
| gl.bindTexture(GL_TEXTURE_2D, m_result_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, 1, /* We will only attach the first level of the result texture to the FBO */ |
| GL_RGBA8, m_view_width, m_view_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestBaseAndMaxLevels::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Only execute if GL_ARB_texture_view extension is supported */ |
| const std::vector<std::string>& extensions = m_context.getContextInfo().getExtensions(); |
| |
| if (std::find(extensions.begin(), extensions.end(), "GL_ARB_texture_view") == extensions.end()) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported"); |
| } |
| |
| /* Initialize all GL objects necessary to run the test */ |
| initTest(); |
| |
| /* Activate test-wide program object */ |
| gl.useProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| /* Bind the data texture */ |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* We will now use the program to sample the view's LOD 0 and LOD 1 and store |
| * it in two separate textures. |
| **/ |
| for (unsigned int lod_level = 0; lod_level < 2; /* as per test spec */ |
| ++lod_level) |
| { |
| /* Set up FBO attachments */ |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed"); |
| |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_result_to_id, |
| 0); /* level */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed"); |
| |
| /* Update viewport configuration */ |
| gl.viewport(0, /* x */ |
| 0, /* y */ |
| m_view_width >> lod_level, m_view_height >> lod_level); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed"); |
| |
| /* Configure program object uniforms before we continue */ |
| gl.uniform1i(m_po_lod_index_uniform_location, lod_level); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| |
| /* Render a triangle strip. The program we're using will output a full-screen |
| * quad with the sampled data */ |
| gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| |
| /* At the time of the draw call, we've modified the draw/read framebuffer binding |
| * so that everything we render ends up in result texture. It's time to read it */ |
| glw::GLvoid* result_data_ptr = (lod_level == 0) ? m_layer_data_lod0 : m_layer_data_lod1; |
| |
| gl.readPixels(0, /* x */ |
| 0, /* y */ |
| m_view_width >> lod_level, m_view_height >> lod_level, GL_RGBA, GL_UNSIGNED_BYTE, |
| result_data_ptr); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed"); |
| } /* for (both LODs) */ |
| |
| /* Now that we have both pieces of data, we can proceed with actual verification */ |
| for (unsigned int lod_level = 0; lod_level < 2; ++lod_level) |
| { |
| /* NOTE: This code is a modification of initialization routine |
| * found in initTextures() |
| */ |
| const unsigned char epsilon = 1; |
| const glw::GLvoid* layer_data_ptr = (lod_level == 0) ? m_layer_data_lod0 : m_layer_data_lod1; |
| const unsigned int layer_height = m_view_height >> lod_level; |
| const unsigned int layer_width = m_view_width >> lod_level; |
| const unsigned int pixel_size = 4 /* components */; |
| const unsigned int view_minimum_level = 1; /* THS SHOULD BE 1 */ |
| const float start_rgba[] = { |
| /* As per test specification */ |
| float(lod_level + view_minimum_level + 0) / 10.0f, float(lod_level + view_minimum_level + 1) / 10.0f, |
| float(lod_level + view_minimum_level + 2) / 10.0f, float(lod_level + view_minimum_level + 3) / 10.0f |
| }; |
| const float end_rgba[] = { float(10 - (lod_level + view_minimum_level + 0)) / 10.0f, |
| float(10 - (lod_level + view_minimum_level + 1)) / 10.0f, |
| float(10 - (lod_level + view_minimum_level + 2)) / 10.0f, |
| float(10 - (lod_level + view_minimum_level + 3)) / 10.0f }; |
| |
| for (unsigned int y = 0; y < layer_height; ++y) |
| { |
| const unsigned char* row_data_ptr = (const unsigned char*)layer_data_ptr + layer_width * y * pixel_size; |
| |
| for (unsigned int x = 0; x < layer_width; ++x) |
| { |
| const float lerp_factor = float(x) / float(layer_width); |
| const unsigned char* pixel_data_ptr = row_data_ptr + x * pixel_size; |
| |
| const unsigned char expected_data[] = { |
| (unsigned char)((start_rgba[0] * lerp_factor + end_rgba[0] * (1.0f - lerp_factor)) * 255.0f), |
| (unsigned char)((start_rgba[1] * lerp_factor + end_rgba[1] * (1.0f - lerp_factor)) * 255.0f), |
| (unsigned char)((start_rgba[2] * lerp_factor + end_rgba[2] * (1.0f - lerp_factor)) * 255.0f), |
| (unsigned char)((start_rgba[3] * lerp_factor + end_rgba[3] * (1.0f - lerp_factor)) * 255.0f) |
| }; |
| |
| if (de::abs(expected_data[0] - pixel_data_ptr[0]) > epsilon || |
| de::abs(expected_data[1] - pixel_data_ptr[1]) > epsilon || |
| de::abs(expected_data[2] - pixel_data_ptr[2]) > epsilon || |
| de::abs(expected_data[3] - pixel_data_ptr[3]) > epsilon) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Found an invalid texel at (" << x << ", " << y |
| << ");" |
| " expected value:" |
| "(" |
| << expected_data[0] << ", " << expected_data[1] << ", " << expected_data[2] |
| << ", " << expected_data[3] << ")" |
| ", found:" |
| "(" |
| << pixel_data_ptr[0] << ", " << pixel_data_ptr[1] << ", " << pixel_data_ptr[2] |
| << ", " << pixel_data_ptr[3] << ")" << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Rendered data does not match expected pixel data"); |
| } /* if (pixel mismatch found) */ |
| } /* for (all columns) */ |
| } /* for (all rows) */ |
| } /* for (both LODs) */ |
| |
| /* Test case passed */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| **/ |
| TextureViewTestReferenceCounting::TextureViewTestReferenceCounting(deqp::Context& context) |
| : TestCase(context, "reference_counting", |
| "Makes sure that sampling from views, for which the parent texture object " |
| "has already been deleted, works correctly.") |
| , m_bo_id(0) |
| , m_parent_to_id(0) |
| , m_po_id(0) |
| , m_po_expected_texel_uniform_location(-1) |
| , m_po_lod_uniform_location(-1) |
| , m_vao_id(0) |
| , m_view_to_id(0) |
| , m_view_view_to_id(0) |
| , m_vs_id(0) |
| , m_texture_height(64) |
| , m_texture_n_levels(7) |
| , m_texture_width(64) |
| { |
| /* Configure a vector storing unique colors that should be used |
| * for filling subsequent mip-maps of parent texture */ |
| m_mipmap_colors.push_back(_norm_vec4(123, 34, 56, 78)); |
| m_mipmap_colors.push_back(_norm_vec4(234, 45, 67, 89)); |
| m_mipmap_colors.push_back(_norm_vec4(34, 56, 78, 90)); |
| m_mipmap_colors.push_back(_norm_vec4(45, 67, 89, 1)); |
| m_mipmap_colors.push_back(_norm_vec4(56, 78, 90, 123)); |
| m_mipmap_colors.push_back(_norm_vec4(67, 89, 1, 234)); |
| m_mipmap_colors.push_back(_norm_vec4(78, 90, 12, 34)); |
| |
| DE_ASSERT(m_mipmap_colors.size() == m_texture_n_levels); |
| } |
| |
| /** Deinitializes all GL objects that may have been created during test |
| * execution. |
| **/ |
| void TextureViewTestReferenceCounting::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id); |
| |
| m_bo_id = 0; |
| } |
| |
| if (m_parent_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_parent_to_id); |
| |
| m_parent_to_id = 0; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| |
| if (m_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_to_id); |
| |
| m_view_to_id = 0; |
| } |
| |
| if (m_view_view_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_view_view_to_id); |
| |
| m_view_view_to_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /* Initializes a program object to be used during the test. */ |
| void TextureViewTestReferenceCounting::initProgram() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Create program & shader object IDs */ |
| m_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed"); |
| |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed"); |
| |
| /* Set vertex shader body */ |
| const char* vs_body = "#version 400\n" |
| "\n" |
| "uniform vec4 expected_texel;\n" |
| "uniform int lod;\n" |
| "uniform sampler2D sampler;\n" |
| "\n" |
| "out int has_passed;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 data = textureLod(sampler, vec2(0.5, 0.5), lod);\n" |
| " const float epsilon = 1.0 / 256.0;\n" |
| "\n" |
| " if (abs(data.r - expected_texel.r) > epsilon ||\n" |
| " abs(data.g - expected_texel.g) > epsilon ||\n" |
| " abs(data.b - expected_texel.b) > epsilon ||\n" |
| " abs(data.a - expected_texel.a) > epsilon)\n" |
| " {\n" |
| " has_passed = 0;\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " has_passed = 1;\n" |
| " }\n" |
| "}\n"; |
| |
| gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, NULL /* length */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed"); |
| |
| /* Configure XFB */ |
| const char* varying_name = "has_passed"; |
| |
| gl.transformFeedbackVaryings(m_po_id, 1 /* count */, &varying_name, GL_INTERLEAVED_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed"); |
| |
| /* Attach the shader object to the program */ |
| gl.attachShader(m_po_id, m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed"); |
| |
| /* Compile the shader */ |
| gl.compileShader(m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| /* Make sure the compilation has succeeded */ |
| glw::GLint compile_status = GL_FALSE; |
| |
| gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed" << tcu::TestLog::EndMessage; |
| } |
| |
| /* Link the program object */ |
| gl.linkProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed"); |
| |
| /* Make sure the program object has linked successfully */ |
| glw::GLint link_status = GL_FALSE; |
| |
| gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed"); |
| |
| if (link_status != GL_TRUE) |
| { |
| TCU_FAIL("Program linking failed"); |
| } |
| |
| /* Retrieve uniform locations */ |
| m_po_expected_texel_uniform_location = gl.getUniformLocation(m_po_id, "expected_texel"); |
| m_po_lod_uniform_location = gl.getUniformLocation(m_po_id, "lod"); |
| |
| if (m_po_expected_texel_uniform_location == -1) |
| { |
| TCU_FAIL("expected_texel is considered an inactive uniform which is invalid"); |
| } |
| |
| if (m_po_lod_uniform_location == -1) |
| { |
| TCU_FAIL("lod is considered an inactive uniform which is invalid"); |
| } |
| } |
| |
| /** Initializes all texture objects and all views used by the test. */ |
| void TextureViewTestReferenceCounting::initTextures() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate texture IDs */ |
| gl.genTextures(1, &m_parent_to_id); |
| gl.genTextures(1, &m_view_to_id); |
| gl.genTextures(1, &m_view_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed"); |
| |
| /* Set up parent texture object A */ |
| gl.bindTexture(GL_TEXTURE_2D, m_parent_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed"); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, m_texture_n_levels, GL_RGBA8, m_texture_width, m_texture_height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed"); |
| |
| /* Set up view B */ |
| gl.textureView(m_view_to_id, GL_TEXTURE_2D, m_parent_to_id, GL_RGBA8, 0, /* minlevel */ |
| m_texture_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed"); |
| |
| /* Set up view C */ |
| gl.textureView(m_view_view_to_id, GL_TEXTURE_2D, m_view_to_id, GL_RGBA8, 0, /* minlevel */ |
| m_texture_n_levels, 0, /* minlayer */ |
| 1); /* numlayers */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTextureView() call failed"); |
| |
| /* Fill parent texture mip-maps with different static colors */ |
| unsigned char* texel_data = new unsigned char[m_texture_width * m_texture_height * 4 /* components */]; |
| |
| for (unsigned int n_mipmap = 0; n_mipmap < m_mipmap_colors.size(); n_mipmap++) |
| { |
| const _norm_vec4& mipmap_color = m_mipmap_colors[n_mipmap]; |
| const unsigned int mipmap_height = m_texture_height >> n_mipmap; |
| const unsigned int mipmap_width = m_texture_width >> n_mipmap; |
| |
| for (unsigned int n_texel = 0; n_texel < mipmap_height * mipmap_width; ++n_texel) |
| { |
| unsigned char* texel_data_ptr = texel_data + n_texel * sizeof(mipmap_color.rgba); |
| |
| memcpy(texel_data_ptr, mipmap_color.rgba, sizeof(mipmap_color.rgba)); |
| } /* for (all relevant mip-map texels) */ |
| |
| /* Upload new mip-map contents */ |
| gl.texSubImage2D(GL_TEXTURE_2D, n_mipmap, 0, /* xoffset */ |
| 0, /* yoffset */ |
| m_texture_width >> n_mipmap, m_texture_height >> n_mipmap, GL_RGBA, GL_UNSIGNED_BYTE, |
| texel_data); |
| |
| if (gl.getError() != GL_NO_ERROR) |
| { |
| delete[] texel_data; |
| texel_data = NULL; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed"); |
| } |
| } /* for (all mip-maps) */ |
| |
| delete[] texel_data; |
| texel_data = NULL; |
| } |
| |
| /* Initialize all GL objects necessary to run the test */ |
| void TextureViewTestReferenceCounting::initTest() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Initialize all texture objects */ |
| initTextures(); |
| |
| /* Initialize test program object */ |
| initProgram(); |
| |
| /* Initialize XFB */ |
| initXFB(); |
| |
| /* Generate and bind a vertex array object, since we'll be doing a number of |
| * draw calls later in the test */ |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); |
| |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); |
| } |
| |
| /** Initializes a buffer object later used for Transform Feedback and binds |
| * it to both general and indexed Transform Feedback binding points. |
| **/ |
| void TextureViewTestReferenceCounting::initXFB() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Sanity checks */ |
| DE_ASSERT(m_po_id != 0); |
| |
| /* Generate a buffer object we'll use for Transform Feedback */ |
| gl.genBuffers(1, &m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); |
| |
| /* Set up buffer object storage. We need it to be large enough to hold |
| * sizeof(glw::GLint) per mipmap level */ |
| const glw::GLint bo_size = (glw::GLint)(sizeof(glw::GLint) * m_mipmap_colors.size()); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed."); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */ |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult TextureViewTestReferenceCounting::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Carry on only if GL_ARB_texture_view extension is supported */ |
| if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_texture_view")) |
| { |
| throw tcu::NotSupportedError("GL_ARB_texture_view is not supported"); |
| } |
| |
| /* Initialize all GL objects used for the test */ |
| initTest(); |
| |
| /* Make sure texture unit 0 is currently active */ |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture() call failed."); |
| |
| /* Activate the test program object */ |
| gl.useProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); |
| |
| /* Run the test in three iterations: |
| * |
| * - Sample both the texture and all the views; once that's finished |
| * successfully, delete the parent texture. |
| * - Sample both views; once that's finished successfully, delete |
| * the first of the views; |
| * - Sample the only remaining view and make sure all mip-maps store |
| * valid colors. |
| **/ |
| for (unsigned int n_iteration = 0; n_iteration < 3; /* iterations in total */ |
| n_iteration++) |
| { |
| glw::GLuint to_ids_to_sample[3] = { 0, 0, 0 }; |
| |
| /* Configure IDs of textures we need to validate for current iteration */ |
| switch (n_iteration) |
| { |
| case 0: |
| { |
| to_ids_to_sample[0] = m_parent_to_id; |
| to_ids_to_sample[1] = m_view_to_id; |
| to_ids_to_sample[2] = m_view_view_to_id; |
| |
| break; |
| } |
| |
| case 1: |
| { |
| to_ids_to_sample[0] = m_view_to_id; |
| to_ids_to_sample[1] = m_view_view_to_id; |
| |
| break; |
| } |
| |
| case 2: |
| { |
| to_ids_to_sample[0] = m_view_view_to_id; |
| |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Invalid iteration index"); |
| } /* switch (n_iteration) */ |
| |
| /* Iterate through all texture objects of our concern */ |
| for (unsigned int n_texture = 0; n_texture < sizeof(to_ids_to_sample) / sizeof(to_ids_to_sample[0]); |
| n_texture++) |
| { |
| glw::GLint to_id = to_ids_to_sample[n_texture]; |
| |
| if (to_id == 0) |
| { |
| /* No texture object to sample from. */ |
| continue; |
| } |
| |
| /* Bind the texture object of our interest to GL_TEXTURE_2D */ |
| gl.bindTexture(GL_TEXTURE_2D, to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| /* Start XFB */ |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); |
| |
| /* Iterate through all mip-maps of the texture we're currently sampling */ |
| for (unsigned int n_mipmap = 0; n_mipmap < m_mipmap_colors.size(); ++n_mipmap) |
| { |
| const _norm_vec4& expected_mipmap_color = m_mipmap_colors[n_mipmap]; |
| |
| /* Update uniforms first */ |
| gl.uniform4f(m_po_expected_texel_uniform_location, (float)(expected_mipmap_color.rgba[0]) / 255.0f, |
| (float)(expected_mipmap_color.rgba[1]) / 255.0f, |
| (float)(expected_mipmap_color.rgba[2]) / 255.0f, |
| (float)(expected_mipmap_color.rgba[3]) / 255.0f); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4f() call failed."); |
| |
| gl.uniform1i(m_po_lod_uniform_location, n_mipmap); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); |
| |
| /* Draw a single point. That'll feed the XFB buffer object with a single bool |
| * indicating if the test passed for the mip-map, or not */ |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); |
| } /* for (all mip-maps) */ |
| |
| /* We're done - close XFB */ |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); |
| |
| /* How did the sampling go? Map the buffer object containing the run |
| * results into process space. |
| */ |
| const glw::GLint* run_results_ptr = |
| (const glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed."); |
| |
| if (run_results_ptr == NULL) |
| { |
| TCU_FAIL("Pointer to mapped buffer object storage is NULL."); |
| } |
| |
| /* Make sure all mip-maps were sampled successfully */ |
| for (unsigned int n_mipmap = 0; n_mipmap < m_mipmap_colors.size(); ++n_mipmap) |
| { |
| if (run_results_ptr[n_mipmap] != 1) |
| { |
| /* Make sure the TF BO is unmapped before we throw the exception */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data was sampled for mip-map level [" |
| << n_mipmap << "] and iteration [" << n_iteration << "]" |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Mip-map sampling failed."); |
| } |
| } /* for (all mip-maps) */ |
| |
| /* Good to unmap the buffer object at this point */ |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); |
| } /* for (all initialized texture objects) */ |
| |
| /* Now that we're done with the iteration, we should delete iteration-specific texture |
| * object. |
| */ |
| switch (n_iteration) |
| { |
| case 0: |
| { |
| gl.deleteTextures(1, &m_parent_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call failed."); |
| |
| m_parent_to_id = 0; |
| break; |
| } |
| |
| case 1: |
| { |
| gl.deleteTextures(1, &m_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call failed."); |
| |
| m_view_to_id = 0; |
| break; |
| } |
| |
| case 2: |
| { |
| gl.deleteTextures(1, &m_view_view_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() call failed."); |
| |
| m_view_view_to_id = 0; |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Invalid iteration index"); |
| } /* switch (n_iteration) */ |
| } /* for (all iterations) */ |
| |
| /* Test case passed */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| **/ |
| TextureViewTests::TextureViewTests(deqp::Context& context) |
| : TestCaseGroup(context, "texture_view", "Verifies \"texture view\" functionality") |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Initializes a texture_storage_multisample test group. |
| * |
| **/ |
| void TextureViewTests::init(void) |
| { |
| addChild(new TextureViewTestGetTexParameter(m_context)); |
| addChild(new TextureViewTestErrors(m_context)); |
| addChild(new TextureViewTestViewSampling(m_context)); |
| addChild(new TextureViewTestViewClasses(m_context)); |
| addChild(new TextureViewTestCoherency(m_context)); |
| addChild(new TextureViewTestBaseAndMaxLevels(m_context)); |
| addChild(new TextureViewTestReferenceCounting(m_context)); |
| } |
| |
| } /* glcts namespace */ |