| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2015-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 |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cCopyImageTests.hpp" |
| |
| #include "gluDefs.hpp" |
| #include "gluStrUtil.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuFloat.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <sstream> |
| |
| #include "deMath.h" |
| |
| /* There are far too much combinations specified for FunctionalTest. |
| * |
| * Following flags controls what is enabled. Set as 1 to enable |
| * all test case from given category, 0 otherwise. |
| * |
| * By default everything is disabled - which still gives 14560 test cases. |
| * |
| * ALL_FORMAT - selects all internal formats, 61 x 61 |
| * ALL_TARGETS - selects all valid targets, 10 x 10 |
| * ALL_IMG_DIM - selects all image dimmensions, 9 x 9 |
| * ALL_REG_DIM - selects all region dimmensions, 7 x 7 |
| * ALL_REG_POS - selects all region positions, like left-top corner, 8 x 8 |
| */ |
| #define COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_FORMATS 0 |
| #define COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_TARGETS 0 |
| #define COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_IMG_DIM 0 |
| #define COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_DIM 0 |
| #define COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS 0 |
| |
| /* The following flags controls if workarounds are enabled */ |
| #define COPY_IMAGE_WRKARD_FORMATS 0 |
| |
| using namespace glw; |
| |
| namespace gl4cts |
| { |
| namespace CopyImage |
| { |
| /** Various utilities used by all tests |
| * |
| **/ |
| class Utils |
| { |
| public: |
| /* Routines */ |
| static bool areFormatsCompatible(glw::GLenum src, glw::GLenum dst); |
| |
| static bool comparePixels(glw::GLenum left_internal_format, const glw::GLdouble& left_red, |
| const glw::GLdouble& left_green, const glw::GLdouble& left_blue, |
| const glw::GLdouble& left_alpha, glw::GLenum right_internal_format, |
| const glw::GLdouble& right_red, const glw::GLdouble& right_green, |
| const glw::GLdouble& right_blue, const glw::GLdouble& right_alpha); |
| |
| static bool comparePixels(glw::GLuint left_pixel_size, const glw::GLubyte* left_pixel_data, |
| glw::GLuint right_pixel_size, const glw::GLubyte* right_pixel_data); |
| |
| static void deleteTexture(deqp::Context& context, glw::GLenum target, glw::GLuint name); |
| |
| static bool isTargetMultilayer(glw::GLenum target); |
| static bool isTargetMultilevel(glw::GLenum target); |
| static bool isTargetMultisampled(glw::GLenum target); |
| |
| static glw::GLuint generateTexture(deqp::Context& context, glw::GLenum target); |
| |
| static void maskPixelForFormat(glw::GLenum internal_format, glw::GLubyte* pixel); |
| |
| static glw::GLdouble getEpsilon(glw::GLenum internal_format); |
| static glw::GLuint getPixelSizeForFormat(glw::GLenum internal_format); |
| static glw::GLenum getFormat(glw::GLenum internal_format); |
| static glw::GLuint getNumberOfChannels(glw::GLenum internal_format); |
| |
| static std::string getPixelString(glw::GLenum internal_format, const glw::GLubyte* pixel); |
| |
| static glw::GLenum getType(glw::GLenum internal_format); |
| static void makeTextureComplete(deqp::Context& context, glw::GLenum target, glw::GLuint id, glw::GLint base_level, |
| glw::GLint max_level); |
| |
| static glw::GLuint prepareCompressedTex(deqp::Context& context, glw::GLenum target, glw::GLenum internal_format); |
| |
| static glw::GLuint prepareMultisampleTex(deqp::Context& context, glw::GLenum target, glw::GLsizei n_samples); |
| |
| static glw::GLuint prepareRenderBuffer(deqp::Context& context, glw::GLenum internal_format); |
| |
| static glw::GLuint prepareTex16x16x6(deqp::Context& context, glw::GLenum target, glw::GLenum internal_format, |
| glw::GLenum format, glw::GLenum type, glw::GLuint& out_buf_id); |
| |
| static void prepareTexture(deqp::Context& context, glw::GLuint name, glw::GLenum target, |
| glw::GLenum internal_format, glw::GLenum format, glw::GLenum type, glw::GLuint level, |
| glw::GLuint width, glw::GLuint height, glw::GLuint depth, const glw::GLvoid* pixels, |
| glw::GLuint& out_buf_id); |
| |
| static glw::GLenum transProxyToRealTarget(glw::GLenum target); |
| static glw::GLenum transRealToBindTarget(glw::GLenum target); |
| |
| static void readChannel(glw::GLenum type, glw::GLuint channel, const glw::GLubyte* pixel, glw::GLdouble& out_value); |
| |
| static void writeChannel(glw::GLenum type, glw::GLuint channel, glw::GLdouble value, glw::GLubyte* pixel); |
| |
| static void packPixel(glw::GLenum internal_format, glw::GLenum type, glw::GLdouble red, glw::GLdouble green, |
| glw::GLdouble blue, glw::GLdouble alpha, glw::GLubyte* out_pixel); |
| |
| static void unpackPixel(glw::GLenum format, glw::GLenum type, const glw::GLubyte* pixel, glw::GLdouble& out_red, |
| glw::GLdouble& out_green, glw::GLdouble& out_blue, glw::GLdouble& out_alpha); |
| |
| static bool unpackAndComaprePixels(glw::GLenum left_format, glw::GLenum left_type, glw::GLenum left_internal_format, |
| const glw::GLubyte* left_pixel, glw::GLenum right_format, glw::GLenum right_type, |
| glw::GLenum right_internal_format, const glw::GLubyte* right_pixel); |
| |
| static inline bool roundComponent(glw::GLenum internal_format, glw::GLenum component, glw::GLdouble& value); |
| }; |
| |
| /* Global constants */ |
| static const GLenum s_internal_formats[] = { |
| /* R8 */ |
| GL_R8, GL_R8I, GL_R8UI, GL_R8_SNORM, |
| |
| /* R16 */ |
| GL_R16, GL_R16F, GL_R16I, GL_R16UI, GL_R16_SNORM, |
| |
| /* R32 */ |
| GL_R32F, GL_R32I, GL_R32UI, |
| |
| /* RG8 */ |
| GL_RG8, GL_RG8I, GL_RG8UI, GL_RG8_SNORM, |
| |
| /* RG16 */ |
| GL_RG16, GL_RG16F, GL_RG16I, GL_RG16UI, GL_RG16_SNORM, |
| |
| /* RG32 */ |
| GL_RG32F, GL_RG32I, GL_RG32UI, |
| |
| /* RGB8 */ |
| GL_RGB8, GL_RGB8I, GL_RGB8UI, GL_RGB8_SNORM, |
| |
| /* RGB16 */ |
| GL_RGB16, GL_RGB16F, GL_RGB16I, GL_RGB16UI, GL_RGB16_SNORM, |
| |
| /* RGB32 */ |
| GL_RGB32F, GL_RGB32I, GL_RGB32UI, |
| |
| /* RGBA8 */ |
| GL_RGBA8, GL_RGBA8I, GL_RGBA8UI, GL_RGBA8_SNORM, |
| |
| /* RGBA16 */ |
| GL_RGBA16, GL_RGBA16F, GL_RGBA16I, GL_RGBA16UI, GL_RGBA16_SNORM, |
| |
| /* RGBA32 */ |
| GL_RGBA32F, GL_RGBA32I, GL_RGBA32UI, |
| |
| /* 8 */ |
| GL_R3_G3_B2, GL_RGBA2, |
| |
| /* 12 */ |
| GL_RGB4, |
| |
| /* 15 */ |
| GL_RGB5, |
| |
| /* 16 */ |
| GL_RGBA4, GL_RGB5_A1, |
| |
| /* 30 */ |
| GL_RGB10, |
| |
| /* 32 */ |
| GL_RGB10_A2, GL_RGB10_A2UI, GL_R11F_G11F_B10F, GL_RGB9_E5, |
| |
| /* 36 */ |
| GL_RGB12, |
| |
| /* 48 */ |
| GL_RGBA12, |
| }; |
| |
| static const GLenum s_invalid_targets[] = { |
| GL_TEXTURE_BUFFER, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_X, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_X, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_Y, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_Z, |
| GL_PROXY_TEXTURE_1D, |
| GL_PROXY_TEXTURE_1D_ARRAY, |
| GL_PROXY_TEXTURE_2D, |
| GL_PROXY_TEXTURE_2D_ARRAY, |
| GL_PROXY_TEXTURE_2D_MULTISAMPLE, |
| GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY, |
| GL_PROXY_TEXTURE_3D, |
| GL_PROXY_TEXTURE_CUBE_MAP, |
| GL_PROXY_TEXTURE_CUBE_MAP_ARRAY, |
| GL_PROXY_TEXTURE_RECTANGLE, |
| }; |
| |
| static const GLenum s_valid_targets[] = { |
| GL_RENDERBUFFER, |
| 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, |
| }; |
| |
| static const GLuint s_n_internal_formats = sizeof(s_internal_formats) / sizeof(s_internal_formats[0]); |
| static const GLuint s_n_invalid_targets = sizeof(s_invalid_targets) / sizeof(s_invalid_targets[0]); |
| static const GLuint s_n_valid_targets = sizeof(s_valid_targets) / sizeof(s_valid_targets[0]); |
| |
| /** |
| * Pixel compatibility depends on pixel size. However value returned by getPixelSizeForFormat |
| * needs some refinements |
| * |
| * @param internal_format Internal format of image |
| * |
| * @return Size of pixel for compatibility checks |
| **/ |
| GLuint getPixelSizeForCompatibilityVerification(GLenum internal_format) |
| { |
| GLuint size = Utils::getPixelSizeForFormat(internal_format); |
| |
| switch (internal_format) |
| { |
| case GL_RGBA2: |
| size = 1; |
| break; |
| default: |
| break; |
| } |
| |
| return size; |
| } |
| |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_FORMATS == 0 |
| |
| /** Filters out formats that should not be tested by FunctionalTest |
| * |
| * @param format Internal format |
| * |
| * @return true if format should be tested, false otherwise |
| **/ |
| bool filterFormats(GLenum format) |
| { |
| bool result = true; |
| |
| switch (format) |
| { |
| /* R8 */ |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R8_SNORM: |
| |
| /* R16 */ |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R16_SNORM: |
| |
| /* R32 */ |
| case GL_R32F: |
| case GL_R32I: |
| case GL_R32UI: |
| |
| /* RG8 */ |
| case GL_RG8: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG8_SNORM: |
| |
| /* RG16 */ |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG16_SNORM: |
| |
| /* RG32 */ |
| case GL_RG32F: |
| case GL_RG32I: |
| case GL_RG32UI: |
| |
| /* RGB8 */ |
| case GL_RGB8: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB8_SNORM: |
| |
| /* RGB16 */ |
| case GL_RGB16: |
| case GL_RGB16F: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB16_SNORM: |
| |
| /* RGB32 */ |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| |
| /* RGBA8 */ |
| case GL_RGBA8: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGBA8_SNORM: |
| |
| /* RGBA16 */ |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA16_SNORM: |
| |
| /* RGBA32 */ |
| case GL_RGBA32F: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| result = false; |
| break; |
| |
| default: |
| result = true; |
| break; |
| } |
| |
| return result; |
| } |
| |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_FORMATS */ |
| |
| /** Checks if two internal_formats are compatible |
| * |
| * @param src Internal format of source image |
| * @param dst Internal format of destination image |
| * |
| * @return true for compatible formats, false otherwise |
| **/ |
| bool Utils::areFormatsCompatible(glw::GLenum src, glw::GLenum dst) |
| { |
| const GLuint dst_size = getPixelSizeForCompatibilityVerification(dst); |
| const GLuint src_size = getPixelSizeForCompatibilityVerification(src); |
| |
| if (dst_size != src_size) |
| { |
| return false; |
| } |
| |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_FORMATS == 0 |
| |
| if ((false == filterFormats(src)) || (false == filterFormats(dst))) |
| { |
| return false; |
| } |
| |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_FORMATS */ |
| |
| if (src != dst) |
| { |
| if ((GL_R3_G3_B2 == dst) || (GL_R3_G3_B2 == src) || (GL_RGBA2 == dst) || (GL_RGBA2 == src) || |
| (GL_RGBA4 == dst) || (GL_RGBA4 == src) || (GL_RGB5_A1 == dst) || (GL_RGB5_A1 == src) || (GL_RGB10 == dst) || |
| (GL_RGB10 == src)) |
| { |
| return false; |
| } |
| } |
| |
| #if COPY_IMAGE_WRKARD_FORMATS |
| |
| if ((GL_RGB10_A2 == src) && (GL_R11F_G11F_B10F == dst) || (GL_RGB10_A2 == src) && (GL_RGB9_E5 == dst) || |
| (GL_RGB10_A2UI == src) && (GL_R11F_G11F_B10F == dst) || (GL_RGB10_A2UI == src) && (GL_RGB9_E5 == dst) || |
| (GL_RGB9_E5 == src) && (GL_RGB10_A2 == dst) || (GL_RGB9_E5 == src) && (GL_RGB10_A2UI == dst) || |
| (GL_R11F_G11F_B10F == src) && (GL_RGB10_A2 == dst) || (GL_R11F_G11F_B10F == src) && (GL_RGB10_A2UI == dst)) |
| { |
| return false; |
| } |
| |
| #endif /* COPY_IMAGE_WRKARD_FORMATS */ |
| |
| if (2 == dst_size) |
| { |
| if (src == dst) |
| { |
| return true; |
| } |
| |
| if (((GL_RGB4 == src) && (GL_RGB4 != dst)) || ((GL_RGB4 != src) && (GL_RGB4 == dst)) || |
| ((GL_RGB5 == src) && (GL_RGB5 != dst)) || ((GL_RGB5 != src) && (GL_RGB5 == dst))) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| if (4 == dst_size) |
| { |
| if (src == dst) |
| { |
| return true; |
| } |
| |
| return true; |
| } |
| |
| return true; |
| } |
| |
| /** Compare two pixels |
| * |
| * @param left_internal_format Internal format of left image |
| * @param left_red Red channel of left image |
| * @param left_green Green channel of left image |
| * @param left_blue Blue channel of left image |
| * @param left_alpha Alpha channel of left image |
| * @param right_internal_format Internal format of right image |
| * @param right_red Red channel of right image |
| * @param right_green Green channel of right image |
| * @param right_blue Blue channel of right image |
| * @param right_alpha Alpha channel of right image |
| * |
| * @return true if pixels match, false otherwise |
| **/ |
| bool Utils::comparePixels(GLenum left_internal_format, const GLdouble& left_red, const GLdouble& left_green, |
| const GLdouble& left_blue, const GLdouble& left_alpha, GLenum right_internal_format, |
| const GLdouble& right_red, const GLdouble& right_green, const GLdouble& right_blue, |
| const GLdouble& right_alpha) |
| { |
| const GLuint left_n_channels = getNumberOfChannels(left_internal_format); |
| const GLuint right_n_channels = getNumberOfChannels(right_internal_format); |
| const GLuint n_channels = (left_n_channels >= right_n_channels) ? right_n_channels : left_n_channels; |
| |
| const GLdouble left_channels[4] = { left_red, left_green, left_blue, left_alpha }; |
| |
| const GLdouble right_channels[4] = { right_red, right_green, right_blue, right_alpha }; |
| |
| for (GLuint i = 0; i < n_channels; ++i) |
| { |
| const GLdouble left = left_channels[i]; |
| const GLdouble right = right_channels[i]; |
| const GLdouble left_eps = getEpsilon(left_internal_format); |
| const GLdouble right_eps = getEpsilon(right_internal_format); |
| const GLdouble eps = fabs(std::max(left_eps, right_eps)); |
| |
| if (eps < fabs(left - right)) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Compare two pixels with memcmp |
| * |
| * @param left_pixel_size Size of left pixel |
| * @param left_pixel_data Data of left pixel |
| * @param right_pixel_size Size of right pixel |
| * @param right_pixel_data Data of right pixel |
| * |
| * @return true if memory match, false otherwise |
| **/ |
| bool Utils::comparePixels(GLuint left_pixel_size, const GLubyte* left_pixel_data, GLuint right_pixel_size, |
| const GLubyte* right_pixel_data) |
| { |
| const GLuint pixel_size = (left_pixel_size >= right_pixel_size) ? left_pixel_size : right_pixel_size; |
| |
| return 0 == memcmp(left_pixel_data, right_pixel_data, pixel_size); |
| } |
| |
| /** Delete texture or renderbuffer |
| * |
| * @param context Test context |
| * @param target Image target |
| * @param name Name of image |
| **/ |
| void Utils::deleteTexture(deqp::Context& context, GLenum target, GLuint name) |
| { |
| const Functions& gl = context.getRenderContext().getFunctions(); |
| |
| if (GL_RENDERBUFFER == target) |
| { |
| gl.deleteRenderbuffers(1, &name); |
| } |
| else |
| { |
| gl.deleteTextures(1, &name); |
| } |
| } |
| |
| /** Get epsilon for given internal_format |
| * |
| * @param internal_format Internal format of image |
| * |
| * @return Epsilon value |
| **/ |
| GLdouble Utils::getEpsilon(GLenum internal_format) |
| { |
| GLdouble epsilon; |
| |
| switch (internal_format) |
| { |
| case GL_R8: |
| case GL_R8_SNORM: |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16_SNORM: |
| case GL_R32F: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32I: |
| case GL_R32UI: |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16_SNORM: |
| case GL_RG32F: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG32I: |
| case GL_RG32UI: |
| case GL_R3_G3_B2: |
| case GL_RGB4: |
| case GL_RGB5: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_R11F_G11F_B10F: |
| case GL_RGB16: |
| case GL_RGB16F: |
| case GL_RGB16_SNORM: |
| case GL_RGB32F: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB10: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| case GL_RGB9_E5: |
| case GL_RGBA2: |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_RGB10_A2: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA32F: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGB10_A2UI: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| epsilon = 0.0; |
| break; |
| case GL_RGB12: |
| case GL_RGBA12: |
| epsilon = 0.00390625; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| return epsilon; |
| } |
| |
| /** Get format for given internal format |
| * |
| * @param internal_format Internal format |
| * |
| * @return Format |
| **/ |
| GLenum Utils::getFormat(GLenum internal_format) |
| { |
| GLenum format = 0; |
| |
| switch (internal_format) |
| { |
| /* R */ |
| case GL_R8: |
| case GL_R8_SNORM: |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16_SNORM: |
| case GL_R32F: |
| format = GL_RED; |
| break; |
| |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32I: |
| case GL_R32UI: |
| format = GL_RED_INTEGER; |
| break; |
| |
| /* RG */ |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16_SNORM: |
| case GL_RG32F: |
| format = GL_RG; |
| break; |
| |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG32I: |
| case GL_RG32UI: |
| format = GL_RG_INTEGER; |
| break; |
| |
| /* RGB */ |
| case GL_R3_G3_B2: |
| case GL_RGB4: |
| case GL_RGB5: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_R11F_G11F_B10F: |
| case GL_RGB12: |
| case GL_RGB16: |
| case GL_RGB16F: |
| case GL_RGB16_SNORM: |
| case GL_RGB32F: |
| case GL_RGB9_E5: |
| format = GL_RGB; |
| break; |
| |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| format = GL_RGB_INTEGER; |
| break; |
| |
| /* RGBA */ |
| case GL_RGB10: |
| case GL_RGBA2: |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_RGB10_A2: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA32F: |
| format = GL_RGBA; |
| break; |
| |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGB10_A2UI: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| format = GL_RGBA_INTEGER; |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| return format; |
| } |
| |
| /** Get number of channels for given internal_format |
| * |
| * @param internal_format Internal format |
| * |
| * @return Number of channels |
| **/ |
| GLuint Utils::getNumberOfChannels(GLenum internal_format) |
| { |
| GLuint result = 0; |
| |
| switch (internal_format) |
| { |
| case GL_R8: |
| case GL_R8_SNORM: |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16_SNORM: |
| case GL_R32F: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32I: |
| case GL_R32UI: |
| result = 1; |
| break; |
| |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16_SNORM: |
| case GL_RG32F: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG32I: |
| case GL_RG32UI: |
| result = 2; |
| break; |
| |
| case GL_R3_G3_B2: |
| case GL_RGB4: |
| case GL_RGB5: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_RGB10: |
| case GL_R11F_G11F_B10F: |
| case GL_RGB12: |
| case GL_RGB16: |
| case GL_RGB16F: |
| case GL_RGB16_SNORM: |
| case GL_RGB32F: |
| case GL_RGB9_E5: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| result = 3; |
| break; |
| |
| case GL_RGBA2: |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_RGB10_A2: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA32F: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGB10_A2UI: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| result = 4; |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Get type for given internal format |
| * |
| * @param internal_format Internal format |
| * |
| * @return Type |
| **/ |
| GLenum Utils::getType(GLenum internal_format) |
| { |
| GLenum type = 0; |
| |
| switch (internal_format) |
| { |
| case GL_R8: |
| case GL_R8UI: |
| case GL_RG8: |
| case GL_RG8UI: |
| case GL_RGB8: |
| case GL_RGB8UI: |
| case GL_RGBA8: |
| case GL_RGBA8UI: |
| type = GL_UNSIGNED_BYTE; |
| break; |
| |
| case GL_R8_SNORM: |
| case GL_R8I: |
| case GL_RG8_SNORM: |
| case GL_RG8I: |
| case GL_RGB8_SNORM: |
| case GL_RGB8I: |
| case GL_RGBA8_SNORM: |
| case GL_RGBA8I: |
| type = GL_BYTE; |
| break; |
| |
| case GL_R3_G3_B2: |
| type = GL_UNSIGNED_BYTE_3_3_2; |
| break; |
| |
| case GL_RGB4: |
| case GL_RGB5: |
| type = GL_UNSIGNED_SHORT_5_6_5; |
| break; |
| |
| case GL_RGBA2: |
| case GL_RGBA4: |
| type = GL_UNSIGNED_SHORT_4_4_4_4; |
| break; |
| |
| case GL_RGB5_A1: |
| type = GL_UNSIGNED_SHORT_5_5_5_1; |
| break; |
| |
| case GL_RGB10: |
| case GL_RGB10_A2: |
| case GL_RGB10_A2UI: |
| type = GL_UNSIGNED_INT_2_10_10_10_REV; |
| break; |
| |
| case GL_R16F: |
| case GL_RG16F: |
| case GL_RGB16F: |
| case GL_RGBA16F: |
| type = GL_HALF_FLOAT; |
| break; |
| |
| case GL_R16: |
| case GL_R16UI: |
| case GL_RG16: |
| case GL_RG16UI: |
| case GL_RGB12: |
| case GL_RGB16: |
| case GL_RGB16UI: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| case GL_RGBA16UI: |
| type = GL_UNSIGNED_SHORT; |
| break; |
| |
| case GL_R16_SNORM: |
| case GL_R16I: |
| case GL_RG16_SNORM: |
| case GL_RG16I: |
| case GL_RGB16_SNORM: |
| case GL_RGB16I: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA16I: |
| type = GL_SHORT; |
| break; |
| |
| case GL_R32UI: |
| case GL_RG32UI: |
| case GL_RGB32UI: |
| case GL_RGBA32UI: |
| type = GL_UNSIGNED_INT; |
| break; |
| |
| case GL_RGB9_E5: |
| type = GL_UNSIGNED_INT_5_9_9_9_REV; |
| break; |
| |
| case GL_R32I: |
| case GL_RG32I: |
| case GL_RGB32I: |
| case GL_RGBA32I: |
| type = GL_INT; |
| break; |
| |
| case GL_R32F: |
| case GL_RG32F: |
| case GL_RGB32F: |
| case GL_RGBA32F: |
| type = GL_FLOAT; |
| break; |
| |
| case GL_R11F_G11F_B10F: |
| type = GL_UNSIGNED_INT_10F_11F_11F_REV; |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| return type; |
| } |
| |
| /** Returns mask that should be applied to pixel value |
| * |
| * @param internal_format Internal format of texture |
| * @param pixel Pixel data |
| * |
| * @return Mask |
| **/ |
| void Utils::maskPixelForFormat(GLenum internal_format, GLubyte* pixel) |
| { |
| switch (internal_format) |
| { |
| case GL_RGB10: |
| /* UINT_10_10_10_2 - ALPHA will be set to 3*/ |
| pixel[0] |= 0x03; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /** Get size of pixel for given internal format |
| * |
| * @param internal_format Internal format |
| * |
| * @return Number of bytes used by given format |
| **/ |
| GLuint Utils::getPixelSizeForFormat(GLenum internal_format) |
| { |
| GLuint size = 0; |
| |
| switch (internal_format) |
| { |
| /* 8 */ |
| case GL_R8: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R8_SNORM: |
| case GL_R3_G3_B2: |
| size = 1; |
| break; |
| |
| /* 8 */ |
| case GL_RGBA2: |
| size = 2; |
| break; |
| |
| /* 12 */ |
| case GL_RGB4: |
| size = 2; |
| break; |
| |
| /* 15 */ |
| case GL_RGB5: |
| size = 2; |
| break; |
| |
| /* 16 */ |
| case GL_RG8: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG8_SNORM: |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R16_SNORM: |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| size = 2; |
| break; |
| |
| /* 24 */ |
| case GL_RGB8: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB8_SNORM: |
| size = 3; |
| break; |
| |
| /* 30 */ |
| case GL_RGB10: |
| size = 4; |
| break; |
| |
| /* 32 */ |
| case GL_RGBA8: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGBA8_SNORM: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG16_SNORM: |
| case GL_R32F: |
| case GL_R32I: |
| case GL_R32UI: |
| case GL_RGB10_A2: |
| case GL_RGB10_A2UI: |
| case GL_R11F_G11F_B10F: |
| case GL_RGB9_E5: |
| size = 4; |
| break; |
| |
| /* 36 */ |
| case GL_RGB12: |
| size = 6; |
| break; |
| |
| /* 48 */ |
| case GL_RGB16: |
| case GL_RGB16F: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB16_SNORM: |
| size = 6; |
| break; |
| |
| /* 64 */ |
| case GL_RGBA12: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA16_SNORM: |
| case GL_RG32F: |
| case GL_RG32I: |
| case GL_RG32UI: |
| size = 8; |
| break; |
| |
| /* 96 */ |
| case GL_RGB32F: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| size = 12; |
| break; |
| |
| /* 128 */ |
| case GL_RGBA32F: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| size = 16; |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| return size; |
| } |
| |
| /** Prepare string that represents bytes of pixel |
| * |
| * @param internal_format Format |
| * @param pixel Pixel data |
| * |
| * @return String |
| **/ |
| std::string Utils::getPixelString(GLenum internal_format, const GLubyte* pixel) |
| { |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(internal_format); |
| std::stringstream stream; |
| |
| stream << "0x"; |
| |
| for (GLint i = pixel_size - 1; i >= 0; --i) |
| { |
| stream << std::setbase(16) << std::setw(2) << std::setfill('0') << (GLuint)pixel[i]; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Check if target supports multiple layers |
| * |
| * @param target Texture target |
| * |
| * @return true if target is multilayered |
| **/ |
| bool Utils::isTargetMultilayer(GLenum target) |
| { |
| bool result = false; |
| |
| switch (target) |
| { |
| case GL_TEXTURE_1D_ARRAY: |
| case GL_TEXTURE_2D_ARRAY: |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| case GL_TEXTURE_3D: |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| result = true; |
| break; |
| |
| default: |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Check if target supports multiple level |
| * |
| * @param target Texture target |
| * |
| * @return true if target supports mipmaps |
| **/ |
| bool Utils::isTargetMultilevel(GLenum target) |
| { |
| bool result = true; |
| |
| switch (target) |
| { |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| case GL_TEXTURE_RECTANGLE: |
| case GL_RENDERBUFFER: |
| result = false; |
| break; |
| default: |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Check if target is multisampled |
| * |
| * @param target Texture target |
| * |
| * @return true when for multisampled formats, false otherwise |
| **/ |
| bool Utils::isTargetMultisampled(GLenum target) |
| { |
| bool result = false; |
| |
| switch (target) |
| { |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| result = true; |
| break; |
| default: |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Generate texture object |
| * |
| * @param context Test context |
| * @param target Target of texture |
| * |
| * @return Generated name |
| **/ |
| glw::GLuint Utils::generateTexture(deqp::Context& context, GLenum target) |
| { |
| const Functions& gl = context.getRenderContext().getFunctions(); |
| GLuint name = 0; |
| |
| switch (target) |
| { |
| case GL_RENDERBUFFER: |
| gl.genRenderbuffers(1, &name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenRenderbuffers"); |
| break; |
| |
| default: |
| gl.genTextures(1, &name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures"); |
| break; |
| } |
| |
| return name; |
| } |
| |
| /** Sets base and max level parameters of texture to make it complete |
| * |
| * @param context Test context |
| * @param target GLenum representing target of texture that should be created |
| * @param id Id of texture |
| * @param base_level Base level value, eg 0 |
| * @param max_level Max level value, eg 0 |
| **/ |
| void Utils::makeTextureComplete(deqp::Context& context, GLenum target, GLuint id, GLint base_level, GLint max_level) |
| { |
| const Functions& gl = context.getRenderContext().getFunctions(); |
| |
| if (GL_RENDERBUFFER == target) |
| { |
| return; |
| } |
| |
| /* Translate proxies into real targets */ |
| target = transRealToBindTarget(transProxyToRealTarget(target)); |
| |
| gl.bindTexture(target, id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| /* Set levels */ |
| if (GL_TEXTURE_BUFFER != target) |
| { |
| gl.texParameteri(target, GL_TEXTURE_BASE_LEVEL, base_level); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); |
| |
| gl.texParameteri(target, GL_TEXTURE_MAX_LEVEL, max_level); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); |
| |
| /* Integer textures won't be complete with the default min filter |
| * of GL_NEAREST_MIPMAP_LINEAR (or GL_LINEAR for rectangle textures) |
| * and default mag filter of GL_LINEAR, so switch to nearest. |
| */ |
| if (GL_TEXTURE_2D_MULTISAMPLE != target && GL_TEXTURE_2D_MULTISAMPLE_ARRAY != target) |
| { |
| gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| if (GL_TEXTURE_RECTANGLE != target) |
| { |
| gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); |
| } |
| else |
| { |
| gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); |
| } |
| } |
| } |
| |
| /* Clean binding point */ |
| gl.bindTexture(target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| } |
| |
| /** Generate and initialize texture for given target |
| * |
| * @param context Test context |
| * @param target GLenum representing target of texture that should be created |
| * @param n_samples Number of samples |
| * |
| * @return "name" of texture |
| **/ |
| GLuint Utils::prepareMultisampleTex(deqp::Context& context, GLenum target, GLsizei n_samples) |
| { |
| static const GLuint depth = 6; |
| const Functions& gl = context.getRenderContext().getFunctions(); |
| static const GLuint height = 16; |
| static const GLenum internal_format = GL_RGBA8; |
| GLuint name = 0; |
| static const GLuint width = 16; |
| |
| gl.genTextures(1, &name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures"); |
| |
| /* Initialize */ |
| switch (target) |
| { |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| gl.bindTexture(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage2DMultisample(target, n_samples, internal_format, width, height, GL_FALSE /* fixedsamplelocation */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2DMultisample"); |
| |
| break; |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| gl.bindTexture(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage3DMultisample(target, n_samples, internal_format, width, height, depth, |
| GL_FALSE /* fixedsamplelocation */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3DMultisample"); |
| |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* Clean binding point */ |
| gl.bindTexture(target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| return name; |
| } |
| |
| /** Generate and initialize texture for given target |
| * |
| * @param context Test context |
| * @param internal_format Internal format of render buffer |
| * |
| * @return "name" of texture |
| **/ |
| GLuint Utils::prepareRenderBuffer(deqp::Context& context, GLenum internal_format) |
| { |
| const Functions& gl = context.getRenderContext().getFunctions(); |
| static const GLuint height = 16; |
| GLuint name = 0; |
| static const GLuint width = 16; |
| |
| gl.genRenderbuffers(1, &name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenRenderbuffers"); |
| |
| /* Initialize */ |
| gl.bindRenderbuffer(GL_RENDERBUFFER, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindRenderbuffer"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, internal_format, width, height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "RenderbufferStorage"); |
| |
| /* Clean binding point */ |
| gl.bindRenderbuffer(GL_RENDERBUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindRenderbuffer"); |
| |
| return name; |
| } |
| |
| /** Generate and initialize texture for given target |
| * |
| * @param context Test context |
| * @param target GLenum representing target of texture that should be created |
| * @param internal_format <internalformat> |
| * @param format <format> |
| * @param type <type> |
| * @param out_buf_id ID of buffer that will be used for TEXTURE_BUFFER |
| * |
| * @return "name" of texture |
| **/ |
| GLuint Utils::prepareTex16x16x6(deqp::Context& context, GLenum target, GLenum internal_format, GLenum format, |
| GLenum type, GLuint& out_buf_id) |
| { |
| static const GLuint depth = 6; |
| static const GLuint height = 16; |
| static const GLuint level = 0; |
| GLuint name = 0; |
| static const GLchar* pixels = 0; |
| static const GLuint width = 16; |
| |
| name = generateTexture(context, target); |
| |
| prepareTexture(context, name, target, internal_format, format, type, level, width, height, depth, pixels, |
| out_buf_id); |
| |
| return name; |
| } |
| |
| /** Initialize texture |
| * |
| * @param context Test context |
| * @param name Name of texture object |
| * @param target GLenum representing target of texture that should be created |
| * @param internal_format <internalformat> |
| * @param format <format> |
| * @param type <type> |
| * @param level <level> |
| * @param width <width> |
| * @param height <height> |
| * @param depth <depth> |
| * @param pixels <pixels> |
| * @param out_buf_id ID of buffer that will be used for TEXTURE_BUFFER |
| * |
| * @return "name" of texture |
| **/ |
| void Utils::prepareTexture(deqp::Context& context, GLuint name, GLenum target, GLenum internal_format, GLenum format, |
| GLenum type, GLuint level, GLuint width, GLuint height, GLuint depth, const GLvoid* pixels, |
| GLuint& out_buf_id) |
| { |
| static const GLint border = 0; |
| GLenum error = 0; |
| const GLchar* function_name = "unknown"; |
| const Functions& gl = context.getRenderContext().getFunctions(); |
| static const GLsizei samples = 1; |
| |
| /* Translate proxies into real targets */ |
| target = transProxyToRealTarget(target); |
| |
| /* Initialize */ |
| switch (target) |
| { |
| case GL_RENDERBUFFER: |
| gl.bindRenderbuffer(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindRenderbuffer"); |
| |
| gl.renderbufferStorage(target, internal_format, width, height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "RenderbufferStorage"); |
| |
| gl.bindRenderbuffer(target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindRenderbuffer"); |
| |
| break; |
| |
| case GL_TEXTURE_1D: |
| gl.bindTexture(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage1D(target, level, internal_format, width, border, format, type, pixels); |
| error = gl.getError(); |
| function_name = "TexImage1D"; |
| |
| break; |
| |
| case GL_TEXTURE_1D_ARRAY: |
| case GL_TEXTURE_2D: |
| case GL_TEXTURE_RECTANGLE: |
| gl.bindTexture(target, name); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage2D(target, level, internal_format, width, height, border, format, type, pixels); |
| error = gl.getError(); |
| function_name = "TexImage2D"; |
| |
| break; |
| |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| gl.bindTexture(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage2DMultisample(target, samples, internal_format, width, height, GL_FALSE /* fixedsamplelocation */); |
| error = gl.getError(); |
| function_name = "TexImage2DMultisample"; |
| |
| break; |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| gl.bindTexture(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage3DMultisample(target, samples, internal_format, width, height, depth, |
| GL_FALSE /* fixedsamplelocation */); |
| error = gl.getError(); |
| function_name = "TexImage3DMultisample"; |
| |
| break; |
| |
| case GL_TEXTURE_2D_ARRAY: |
| case GL_TEXTURE_3D: |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| gl.bindTexture(target, name); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage3D(target, level, internal_format, width, height, depth, border, format, type, pixels); |
| error = gl.getError(); |
| function_name = "TexImage3D"; |
| |
| break; |
| |
| case GL_TEXTURE_BUFFER: |
| gl.genBuffers(1, &out_buf_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers"); |
| |
| gl.bindBuffer(GL_TEXTURE_BUFFER, out_buf_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer"); |
| |
| { |
| GLsizei size = 16; |
| const GLvoid* data = 0; |
| |
| if (0 != pixels) |
| { |
| size = width; |
| data = pixels; |
| } |
| |
| gl.bufferData(GL_TEXTURE_BUFFER, size, data, GL_DYNAMIC_COPY); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData"); |
| } |
| |
| gl.bindTexture(GL_TEXTURE_BUFFER, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texBuffer(GL_TEXTURE_BUFFER, internal_format, out_buf_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexBuffer"); |
| |
| break; |
| |
| case GL_TEXTURE_CUBE_MAP: |
| 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: |
| /* Change target to CUBE_MAP, it will be used later to change base and max level */ |
| target = GL_TEXTURE_CUBE_MAP; |
| gl.bindTexture(target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, border, format, type, |
| pixels); |
| gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, border, format, type, |
| pixels); |
| gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, border, format, type, |
| pixels); |
| gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, border, format, type, |
| pixels); |
| gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, border, format, type, |
| pixels); |
| gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, border, format, type, |
| pixels); |
| error = gl.getError(); |
| function_name = "TexImage2D"; |
| |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| if (GL_NO_ERROR != error) |
| { |
| context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Error: " << glu::getErrorStr(error) << ". Function: " << function_name |
| << ". Target: " << glu::getTextureTargetStr(target) |
| << ". Format: " << glu::getInternalFormatParameterStr(internal_format) << ", " |
| << glu::getTextureFormatName(format) << ", " << glu::getTypeStr(type) << tcu::TestLog::EndMessage; |
| TCU_FAIL("Failed to create texture"); |
| } |
| |
| if (GL_RENDERBUFFER != target) |
| { |
| /* Clean binding point */ |
| gl.bindTexture(target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| } |
| } |
| |
| /** Translate proxies into real targets |
| * |
| * @param target Target to be converted |
| * |
| * @return Converted target for proxies, <target> otherwise |
| **/ |
| GLenum Utils::transProxyToRealTarget(GLenum target) |
| { |
| switch (target) |
| { |
| case GL_PROXY_TEXTURE_1D: |
| target = GL_TEXTURE_1D; |
| break; |
| case GL_PROXY_TEXTURE_1D_ARRAY: |
| target = GL_TEXTURE_1D_ARRAY; |
| break; |
| case GL_PROXY_TEXTURE_2D: |
| target = GL_TEXTURE_2D; |
| break; |
| case GL_PROXY_TEXTURE_2D_ARRAY: |
| target = GL_TEXTURE_2D_ARRAY; |
| break; |
| case GL_PROXY_TEXTURE_2D_MULTISAMPLE: |
| target = GL_TEXTURE_2D_MULTISAMPLE; |
| break; |
| case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; |
| break; |
| case GL_PROXY_TEXTURE_3D: |
| target = GL_TEXTURE_3D; |
| break; |
| case GL_PROXY_TEXTURE_CUBE_MAP: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: |
| target = GL_TEXTURE_CUBE_MAP_ARRAY; |
| break; |
| case GL_PROXY_TEXTURE_RECTANGLE: |
| target = GL_TEXTURE_RECTANGLE; |
| break; |
| default: |
| break; |
| } |
| |
| return target; |
| } |
| |
| /** Translate real targets into binding targets |
| * |
| * @param target Target to be converted |
| * |
| * @return Converted target for cube map faces, <target> otherwise |
| **/ |
| GLenum Utils::transRealToBindTarget(GLenum target) |
| { |
| switch (target) |
| { |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_X: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: |
| target = GL_TEXTURE_CUBE_MAP; |
| break; |
| default: |
| break; |
| } |
| |
| return target; |
| } |
| |
| /** Read value of channel |
| * |
| * @tparam T Type used to store channel value |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| template <typename T> |
| void readBaseTypeFromUnsignedChannel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| static const T max = -1; |
| |
| const GLdouble d_max = (GLdouble)max; |
| const T* ptr = (T*)pixel; |
| const T t_value = ptr[channel]; |
| const GLdouble d_value = (GLdouble)t_value; |
| |
| out_value = d_value / d_max; |
| } |
| |
| /** Read value of channel |
| * |
| * @tparam T Type used to store channel value |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| template <typename T> |
| void readBaseTypeFromSignedChannel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| static const GLuint n_bytes = sizeof(T); |
| static const GLuint n_bits = 8u * n_bytes; |
| static const T max = (T)((1u << (n_bits - 1u)) - 1u); |
| |
| const GLdouble d_max = (GLdouble)max; |
| const T* ptr = (T*)pixel; |
| const T t_value = ptr[channel]; |
| const GLdouble d_value = (GLdouble)t_value; |
| |
| out_value = d_value / d_max; |
| } |
| |
| /** Read value of channel |
| * |
| * @tparam T Type used to store channel value |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| void readBaseTypeFromFloatChannel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| const GLfloat* ptr = (const GLfloat*)pixel; |
| const GLfloat t_value = ptr[channel]; |
| const GLdouble d_value = (GLdouble)t_value; |
| |
| out_value = d_value; |
| } |
| |
| /** Read value of channel |
| * |
| * @tparam T Type used to store channel value |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| void readBaseTypeFromHalfFloatChannel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| const deUint16* ptr = (const deUint16*)pixel; |
| const deUint16 bits = ptr[channel]; |
| tcu::Float16 val(bits); |
| const GLdouble d_value = val.asDouble(); |
| |
| out_value = d_value; |
| } |
| |
| /** Read value of channel |
| * |
| * @tparam T Type used to store pixel |
| * @tparam size_1 Size of channel in bits |
| * @tparam size_2 Size of channel in bits |
| * @tparam size_3 Size of channel in bits |
| * @tparam off_1 Offset of channel in bits |
| * @tparam off_2 Offset of channel in bits |
| * @tparam off_3 Offset of channel in bits |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| template <typename T, unsigned int size_1, unsigned int size_2, unsigned int size_3, unsigned int off_1, |
| unsigned int off_2, unsigned int off_3> |
| void read3Channel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| T mask = 0; |
| T max = 0; |
| T off = 0; |
| const T* ptr = (T*)pixel; |
| T result = 0; |
| const T t_value = ptr[0]; |
| |
| static const T max_1 = (1 << size_1) - 1; |
| static const T max_2 = (1 << size_2) - 1; |
| static const T max_3 = (1 << size_3) - 1; |
| |
| switch (channel) |
| { |
| case 0: |
| mask = max_1; |
| max = max_1; |
| off = off_1; |
| break; |
| case 1: |
| mask = max_2; |
| max = max_2; |
| off = off_2; |
| break; |
| case 2: |
| mask = max_3; |
| max = max_3; |
| off = off_3; |
| break; |
| default: |
| TCU_FAIL("Invalid channel"); |
| break; |
| } |
| |
| result = (T)((t_value >> off) & mask); |
| |
| const GLdouble d_max = (GLdouble)max; |
| const GLdouble d_value = (GLdouble)result; |
| |
| out_value = d_value / d_max; |
| } |
| |
| /** Read value of channel |
| * |
| * @tparam T Type used to store pixel |
| * @tparam size_1 Size of channel in bits |
| * @tparam size_2 Size of channel in bits |
| * @tparam size_3 Size of channel in bits |
| * @tparam size_4 Size of channel in bits |
| * @tparam off_1 Offset of channel in bits |
| * @tparam off_2 Offset of channel in bits |
| * @tparam off_3 Offset of channel in bits |
| * @tparam off_4 Offset of channel in bits |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| template <typename T, unsigned int size_1, unsigned int size_2, unsigned int size_3, unsigned int size_4, |
| unsigned int off_1, unsigned int off_2, unsigned int off_3, unsigned int off_4> |
| void read4Channel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| T mask = 0; |
| T max = 0; |
| T off = 0; |
| const T* ptr = (T*)pixel; |
| T result = 0; |
| const T t_value = ptr[0]; |
| |
| static const T max_1 = (1 << size_1) - 1; |
| static const T max_2 = (1 << size_2) - 1; |
| static const T max_3 = (1 << size_3) - 1; |
| static const T max_4 = (1 << size_4) - 1; |
| |
| switch (channel) |
| { |
| case 0: |
| mask = max_1; |
| max = max_1; |
| off = off_1; |
| break; |
| case 1: |
| mask = max_2; |
| max = max_2; |
| off = off_2; |
| break; |
| case 2: |
| mask = max_3; |
| max = max_3; |
| off = off_3; |
| break; |
| case 3: |
| mask = max_4; |
| max = max_4; |
| off = off_4; |
| break; |
| default: |
| TCU_FAIL("Invalid channel"); |
| break; |
| } |
| |
| result = (T)((t_value >> off) & mask); |
| |
| const GLdouble d_max = (GLdouble)max; |
| const GLdouble d_value = (GLdouble)result; |
| |
| out_value = d_value / d_max; |
| } |
| |
| /** Read value of channel |
| * |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param out_value Read value |
| **/ |
| void read11F_11F_10F_Channel(GLuint channel, const GLubyte* pixel, GLdouble& out_value) |
| { |
| const deUint32* ptr = (deUint32*)pixel; |
| deUint32 val = *ptr; |
| |
| switch (channel) |
| { |
| case 0: |
| { |
| deUint32 bits = (val & 0x000007ff); |
| tcu::Float<deUint32, 5, 6, 15, tcu::FLOAT_SUPPORT_DENORM> temp_val(bits); |
| |
| out_value = temp_val.asDouble(); |
| } |
| break; |
| case 1: |
| { |
| deUint32 bits = ((val >> 11) & 0x000007ff); |
| tcu::Float<deUint32, 5, 6, 15, tcu::FLOAT_SUPPORT_DENORM> temp_val(bits); |
| |
| out_value = temp_val.asDouble(); |
| } |
| break; |
| case 2: |
| { |
| deUint32 bits = ((val >> 22) & 0x000003ff); |
| tcu::Float<deUint32, 5, 5, 15, tcu::FLOAT_SUPPORT_DENORM> temp_val(bits); |
| |
| out_value = temp_val.asDouble(); |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid channel"); |
| break; |
| } |
| } |
| |
| /** Write value of channel |
| * |
| * @tparam T Type used to store pixel |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| template <typename T> |
| void writeBaseTypeToUnsignedChannel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| static const T max = -1; |
| |
| const GLdouble d_max = (GLdouble)max; |
| const GLdouble d_value = value * d_max; |
| const T t_value = (T)d_value; |
| |
| T* ptr = (T*)pixel; |
| |
| ptr[channel] = t_value; |
| } |
| |
| /** Write value of channel |
| * |
| * @tparam T Type used to store pixel |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| template <typename T> |
| void writeBaseTypeToSignedChannel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| static const GLuint n_bytes = sizeof(T); |
| static const GLuint n_bits = 8u * n_bytes; |
| static const T max = (T)((1u << (n_bits - 1u)) - 1u); |
| |
| const GLdouble d_max = (GLdouble)max; |
| const GLdouble d_value = value * d_max; |
| const T t_value = (T)d_value; |
| |
| T* ptr = (T*)pixel; |
| |
| ptr[channel] = t_value; |
| } |
| |
| /** Write value of channel |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| void writeBaseTypeToFloatChannel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| const GLfloat t_value = (GLfloat)value; |
| |
| GLfloat* ptr = (GLfloat*)pixel; |
| |
| ptr[channel] = t_value; |
| } |
| |
| /** Write value of channel |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| void writeBaseTypeToHalfFloatChannel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| deUint16* ptr = (deUint16*)pixel; |
| |
| tcu::Float16 val(value); |
| |
| ptr[channel] = val.bits(); |
| } |
| |
| /** Write value of channel |
| * |
| * @tparam T Type used to store pixel |
| * @tparam size_1 Size of channel in bits |
| * @tparam size_2 Size of channel in bits |
| * @tparam size_3 Size of channel in bits |
| * @tparam off_1 Offset of channel in bits |
| * @tparam off_2 Offset of channel in bits |
| * @tparam off_3 Offset of channel in bits |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| template <typename T, unsigned int size_1, unsigned int size_2, unsigned int size_3, unsigned int off_1, |
| unsigned int off_2, unsigned int off_3> |
| void write3Channel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| T mask = 0; |
| T max = 0; |
| T off = 0; |
| T* ptr = (T*)pixel; |
| T result = 0; |
| |
| static const T max_1 = (1 << size_1) - 1; |
| static const T max_2 = (1 << size_2) - 1; |
| static const T max_3 = (1 << size_3) - 1; |
| |
| switch (channel) |
| { |
| case 0: |
| mask = max_1; |
| max = max_1; |
| off = off_1; |
| break; |
| case 1: |
| mask = max_2; |
| max = max_2; |
| off = off_2; |
| break; |
| case 2: |
| mask = max_3; |
| max = max_3; |
| off = off_3; |
| break; |
| default: |
| TCU_FAIL("Invalid channel"); |
| break; |
| } |
| |
| const GLdouble d_max = (GLdouble)max; |
| const GLdouble d_value = value * d_max; |
| const T t_value = (T)d_value; |
| |
| result = (T)((t_value & mask) << off); |
| |
| *ptr |= result; |
| } |
| |
| /** Write value of channel |
| * |
| * @tparam T Type used to store pixel |
| * @tparam size_1 Size of channel in bits |
| * @tparam size_2 Size of channel in bits |
| * @tparam size_3 Size of channel in bits |
| * @tparam size_4 Size of channel in bits |
| * @tparam off_1 Offset of channel in bits |
| * @tparam off_2 Offset of channel in bits |
| * @tparam off_3 Offset of channel in bits |
| * @tparam off_4 Offset of channel in bits |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| template <typename T, unsigned int size_1, unsigned int size_2, unsigned int size_3, unsigned int size_4, |
| unsigned int off_1, unsigned int off_2, unsigned int off_3, unsigned int off_4> |
| void write4Channel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| T mask = 0; |
| T max = 0; |
| T off = 0; |
| T* ptr = (T*)pixel; |
| T result = 0; |
| |
| static const T max_1 = (1 << size_1) - 1; |
| static const T max_2 = (1 << size_2) - 1; |
| static const T max_3 = (1 << size_3) - 1; |
| static const T max_4 = (1 << size_4) - 1; |
| |
| switch (channel) |
| { |
| case 0: |
| mask = max_1; |
| max = max_1; |
| off = off_1; |
| break; |
| case 1: |
| mask = max_2; |
| max = max_2; |
| off = off_2; |
| break; |
| case 2: |
| mask = max_3; |
| max = max_3; |
| off = off_3; |
| break; |
| case 3: |
| mask = max_4; |
| max = max_4; |
| off = off_4; |
| break; |
| default: |
| TCU_FAIL("Invalid channel"); |
| break; |
| } |
| |
| const GLdouble d_max = (GLdouble)max; |
| const GLdouble d_value = value * d_max; |
| const T t_value = (T)d_value; |
| |
| result = (T)((t_value & mask) << off); |
| |
| *ptr |= result; |
| } |
| |
| /** Write value of channel |
| * |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| void write11F_11F_10F_Channel(GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| deUint32* ptr = (deUint32*)pixel; |
| |
| switch (channel) |
| { |
| case 0: |
| { |
| tcu::Float<deUint32, 5, 6, 15, tcu::FLOAT_SUPPORT_DENORM> val(value); |
| deUint32 bits = val.bits(); |
| |
| *ptr |= bits; |
| } |
| break; |
| case 1: |
| { |
| tcu::Float<deUint32, 5, 6, 15, tcu::FLOAT_SUPPORT_DENORM> val(value); |
| deUint32 bits = val.bits(); |
| |
| *ptr |= (bits << 11); |
| } |
| break; |
| case 2: |
| { |
| tcu::Float<deUint32, 5, 5, 15, tcu::FLOAT_SUPPORT_DENORM> val(value); |
| deUint32 bits = val.bits(); |
| |
| *ptr |= (bits << 22); |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid channel"); |
| break; |
| } |
| } |
| |
| /** Read value of channel |
| * |
| * @param type Type used by pixel |
| * @param channel Channel index |
| * @param pixel Pixel data |
| * @param value Read value |
| **/ |
| void Utils::readChannel(GLenum type, GLuint channel, const GLubyte* pixel, GLdouble& value) |
| { |
| switch (type) |
| { |
| /* Base types */ |
| case GL_UNSIGNED_BYTE: |
| readBaseTypeFromUnsignedChannel<GLubyte>(channel, pixel, value); |
| break; |
| case GL_UNSIGNED_SHORT: |
| readBaseTypeFromUnsignedChannel<GLushort>(channel, pixel, value); |
| break; |
| case GL_UNSIGNED_INT: |
| readBaseTypeFromUnsignedChannel<GLuint>(channel, pixel, value); |
| break; |
| case GL_BYTE: |
| readBaseTypeFromSignedChannel<GLbyte>(channel, pixel, value); |
| break; |
| case GL_SHORT: |
| readBaseTypeFromSignedChannel<GLshort>(channel, pixel, value); |
| break; |
| case GL_INT: |
| readBaseTypeFromSignedChannel<GLint>(channel, pixel, value); |
| break; |
| case GL_HALF_FLOAT: |
| readBaseTypeFromHalfFloatChannel(channel, pixel, value); |
| break; |
| case GL_FLOAT: |
| readBaseTypeFromFloatChannel(channel, pixel, value); |
| break; |
| |
| /* Complicated */ |
| /* 3 channles */ |
| case GL_UNSIGNED_BYTE_3_3_2: |
| read3Channel<GLubyte, 3, 3, 2, 5, 2, 0>(channel, pixel, value); |
| break; |
| case GL_UNSIGNED_SHORT_5_6_5: |
| read3Channel<GLushort, 5, 6, 5, 11, 5, 0>(channel, pixel, value); |
| break; |
| |
| /* 4 channels */ |
| case GL_UNSIGNED_SHORT_4_4_4_4: |
| read4Channel<GLushort, 4, 4, 4, 4, 12, 8, 4, 0>(channel, pixel, value); |
| break; |
| case GL_UNSIGNED_SHORT_5_5_5_1: |
| read4Channel<GLushort, 5, 5, 5, 1, 11, 6, 1, 0>(channel, pixel, value); |
| break; |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| read4Channel<GLuint, 2, 10, 10, 10, 30, 20, 10, 0>(3 - channel, pixel, value); |
| break; |
| case GL_UNSIGNED_INT_5_9_9_9_REV: |
| read4Channel<GLuint, 5, 9, 9, 9, 27, 18, 9, 0>(3 - channel, pixel, value); |
| break; |
| |
| /* R11F_G11F_B10F - uber complicated */ |
| case GL_UNSIGNED_INT_10F_11F_11F_REV: |
| read11F_11F_10F_Channel(channel, pixel, value); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| /** Write value of channel |
| * |
| * @param type Type used by pixel |
| * @param channel Channel index |
| * @param value Value to write |
| * @param pixel Pixel data |
| **/ |
| void Utils::writeChannel(GLenum type, GLuint channel, GLdouble value, GLubyte* pixel) |
| { |
| switch (type) |
| { |
| /* Base types */ |
| case GL_UNSIGNED_BYTE: |
| writeBaseTypeToUnsignedChannel<GLubyte>(channel, value, pixel); |
| break; |
| case GL_UNSIGNED_SHORT: |
| writeBaseTypeToUnsignedChannel<GLushort>(channel, value, pixel); |
| break; |
| case GL_UNSIGNED_INT: |
| writeBaseTypeToUnsignedChannel<GLuint>(channel, value, pixel); |
| break; |
| case GL_BYTE: |
| writeBaseTypeToSignedChannel<GLbyte>(channel, value, pixel); |
| break; |
| case GL_SHORT: |
| writeBaseTypeToSignedChannel<GLshort>(channel, value, pixel); |
| break; |
| case GL_INT: |
| writeBaseTypeToSignedChannel<GLint>(channel, value, pixel); |
| break; |
| case GL_HALF_FLOAT: |
| writeBaseTypeToHalfFloatChannel(channel, value, pixel); |
| break; |
| case GL_FLOAT: |
| writeBaseTypeToFloatChannel(channel, value, pixel); |
| break; |
| |
| /* Complicated */ |
| |
| /* 3 channles */ |
| case GL_UNSIGNED_BYTE_3_3_2: |
| write3Channel<GLubyte, 3, 3, 2, 5, 2, 0>(channel, value, pixel); |
| break; |
| case GL_UNSIGNED_SHORT_5_6_5: |
| write3Channel<GLushort, 5, 6, 5, 11, 5, 0>(channel, value, pixel); |
| break; |
| |
| /* 4 channels */ |
| case GL_UNSIGNED_SHORT_4_4_4_4: |
| write4Channel<GLushort, 4, 4, 4, 4, 12, 8, 4, 0>(channel, value, pixel); |
| break; |
| case GL_UNSIGNED_SHORT_5_5_5_1: |
| write4Channel<GLushort, 5, 5, 5, 1, 11, 6, 1, 0>(channel, value, pixel); |
| break; |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| write4Channel<GLuint, 2, 10, 10, 10, 30, 20, 10, 0>(3 - channel, value, pixel); |
| break; |
| case GL_UNSIGNED_INT_5_9_9_9_REV: |
| write4Channel<GLuint, 5, 9, 9, 9, 27, 18, 9, 0>(3 - channel, value, pixel); |
| break; |
| |
| /* R11F_G11F_B10F - uber complicated */ |
| case GL_UNSIGNED_INT_10F_11F_11F_REV: |
| write11F_11F_10F_Channel(channel, value, pixel); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| /** Packs given channels to pixel |
| * |
| * @param internal_format Internal format of image |
| * @param type Type used by image |
| * @param red Red channel |
| * @param green Green channel |
| * @param blue Blue channel |
| * @param alpha Alpha channel |
| * @param out_pixel Pixel data |
| **/ |
| void Utils::packPixel(GLenum internal_format, GLenum type, GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha, |
| GLubyte* out_pixel) |
| { |
| switch (internal_format) |
| { |
| case GL_R8: |
| case GL_R8_SNORM: |
| case GL_R16: |
| case GL_R16F: |
| case GL_R16_SNORM: |
| case GL_R32F: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32I: |
| case GL_R32UI: |
| writeChannel(type, 0, red, out_pixel); |
| break; |
| |
| case GL_RG8: |
| case GL_RG8_SNORM: |
| case GL_RG16: |
| case GL_RG16F: |
| case GL_RG16_SNORM: |
| case GL_RG32F: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG32I: |
| case GL_RG32UI: |
| writeChannel(type, 0, red, out_pixel); |
| writeChannel(type, 1, green, out_pixel); |
| break; |
| |
| case GL_R3_G3_B2: |
| case GL_RGB4: |
| case GL_RGB5: |
| case GL_RGB8: |
| case GL_RGB8_SNORM: |
| case GL_RGB10: |
| case GL_R11F_G11F_B10F: |
| case GL_RGB12: |
| case GL_RGB16: |
| case GL_RGB16F: |
| case GL_RGB16_SNORM: |
| case GL_RGB32F: |
| case GL_RGB8I: |
| case GL_RGB8UI: |
| case GL_RGB16I: |
| case GL_RGB16UI: |
| case GL_RGB32I: |
| case GL_RGB32UI: |
| writeChannel(type, 0, red, out_pixel); |
| writeChannel(type, 1, green, out_pixel); |
| writeChannel(type, 2, blue, out_pixel); |
| break; |
| |
| case GL_RGB9_E5: |
| case GL_RGBA2: |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGBA8: |
| case GL_RGBA8_SNORM: |
| case GL_RGB10_A2: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| case GL_RGBA16F: |
| case GL_RGBA16_SNORM: |
| case GL_RGBA32F: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGB10_A2UI: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| writeChannel(type, 0, red, out_pixel); |
| writeChannel(type, 1, green, out_pixel); |
| writeChannel(type, 2, blue, out_pixel); |
| writeChannel(type, 3, alpha, out_pixel); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| /** Unpacks channels from pixel |
| * |
| * @param internal_format Internal format of image |
| * @param type Type used by image |
| * @param pixel Pixel data |
| * @param red Red channel |
| * @param green Green channel |
| * @param blue Blue channel |
| * @param alpha Alpha channel |
| **/ |
| void Utils::unpackPixel(GLenum format, GLenum type, const GLubyte* pixel, GLdouble& out_red, GLdouble& out_green, |
| GLdouble& out_blue, GLdouble& out_alpha) |
| { |
| switch (format) |
| { |
| case GL_RED: |
| case GL_RED_INTEGER: |
| readChannel(type, 0, pixel, out_red); |
| out_green = 1.0; |
| out_blue = 1.0; |
| out_alpha = 1.0; |
| break; |
| case GL_RG: |
| case GL_RG_INTEGER: |
| readChannel(type, 0, pixel, out_red); |
| readChannel(type, 1, pixel, out_green); |
| out_blue = 1.0; |
| out_alpha = 1.0; |
| break; |
| case GL_RGB: |
| case GL_RGB_INTEGER: |
| switch (type) |
| { |
| case GL_UNSIGNED_INT_5_9_9_9_REV: |
| readChannel(type, 0, pixel, out_red); |
| readChannel(type, 1, pixel, out_green); |
| readChannel(type, 2, pixel, out_blue); |
| readChannel(type, 3, pixel, out_alpha); |
| break; |
| default: |
| readChannel(type, 0, pixel, out_red); |
| readChannel(type, 1, pixel, out_green); |
| readChannel(type, 2, pixel, out_blue); |
| out_alpha = 1.0; |
| break; |
| } |
| break; |
| case GL_RGBA: |
| case GL_RGBA_INTEGER: |
| readChannel(type, 0, pixel, out_red); |
| readChannel(type, 1, pixel, out_green); |
| readChannel(type, 2, pixel, out_blue); |
| readChannel(type, 3, pixel, out_alpha); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| inline bool Utils::roundComponent(GLenum internal_format, GLenum component, GLdouble& value) |
| { |
| int exponent = (internal_format == GL_RGB4 ? 4 : (internal_format == GL_RGB5 ? 5 : 0)); |
| if (!exponent) |
| return false; //Currently this only happens with GL_RGB4 and GL_RGB5 when stored as 565 type. |
| |
| int rounded_value = static_cast<int>(floor((pow(2, exponent) - 1) * value + 0.5)); |
| int multiplier = (component == GL_GREEN ? 2 : 1); |
| if (internal_format == GL_RGB4) |
| { |
| multiplier *= 2; |
| } |
| value = rounded_value * multiplier; |
| return true; |
| } |
| |
| /** Unpacks pixels and compars them |
| * |
| * @param left_format Format of left image |
| * @param left_type Type of left image |
| * @param left_internal_format Internal format of left image |
| * @param left_pixel Data of left pixel |
| * @param right_format Format of right image |
| * @param right_type Type of right image |
| * @param right_internal_format Internal format of right image |
| * @param right_pixel Data of right pixel |
| * |
| * @return true if pixels match, false otherwise |
| **/ |
| bool Utils::unpackAndComaprePixels(GLenum left_format, GLenum left_type, GLenum left_internal_format, |
| const GLubyte* left_pixel, GLenum right_format, GLenum right_type, |
| GLenum right_internal_format, const GLubyte* right_pixel) |
| { |
| GLdouble left_red; |
| GLdouble left_green; |
| GLdouble left_blue; |
| GLdouble left_alpha; |
| GLdouble right_red; |
| GLdouble right_green; |
| GLdouble right_blue; |
| GLdouble right_alpha; |
| |
| unpackPixel(left_format, left_type, left_pixel, left_red, left_green, left_blue, left_alpha); |
| |
| unpackPixel(right_format, right_type, right_pixel, right_red, right_green, right_blue, right_alpha); |
| |
| roundComponent(left_internal_format, GL_RED, left_red); |
| roundComponent(left_internal_format, GL_GREEN, left_green); |
| roundComponent(left_internal_format, GL_BLUE, left_blue); |
| |
| roundComponent(right_internal_format, GL_RED, right_red); |
| roundComponent(right_internal_format, GL_GREEN, right_green); |
| roundComponent(right_internal_format, GL_BLUE, right_blue); |
| |
| return comparePixels(left_internal_format, left_red, left_green, left_blue, left_alpha, right_internal_format, |
| right_red, right_green, right_blue, right_alpha); |
| } |
| |
| /* FunctionalTest */ |
| #define FUNCTIONAL_TEST_N_LAYERS 12 |
| #define FUNCTIONAL_TEST_N_LEVELS 3 |
| |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| FunctionalTest::FunctionalTest(deqp::Context& context) |
| : TestCase(context, "functional", "Test verifies CopyImageSubData copy data as requested") |
| , m_dst_buf_name(0) |
| , m_dst_tex_name(0) |
| , m_rb_name(0) |
| , m_src_buf_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| for (GLuint src_tgt_id = 0; src_tgt_id < s_n_valid_targets; ++src_tgt_id) |
| { |
| const GLenum src_target = s_valid_targets[src_tgt_id]; |
| |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_TARGETS == 0 |
| if ((GL_TEXTURE_1D == src_target) || (GL_TEXTURE_1D_ARRAY == src_target) || (GL_TEXTURE_2D == src_target) || |
| (GL_TEXTURE_CUBE_MAP == src_target) || (GL_TEXTURE_CUBE_MAP_ARRAY == src_target)) |
| { |
| continue; |
| } |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_TARGETS == 0 */ |
| |
| for (GLuint dst_tgt_id = 0; dst_tgt_id < s_n_valid_targets; ++dst_tgt_id) |
| { |
| const GLenum dst_target = s_valid_targets[dst_tgt_id]; |
| |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_TARGETS == 0 |
| if ((GL_TEXTURE_1D == dst_target) || (GL_TEXTURE_1D_ARRAY == dst_target) || (GL_TEXTURE_2D == dst_target) || |
| (GL_TEXTURE_CUBE_MAP == dst_target) || (GL_TEXTURE_CUBE_MAP_ARRAY == dst_target)) |
| { |
| continue; |
| } |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_TARGETS == 0 */ |
| |
| /* Skip render buffer as destination */ |
| if (GL_RENDERBUFFER == dst_target) |
| { |
| continue; |
| } |
| |
| /* Skip multisampled */ |
| if ((true == Utils::isTargetMultisampled(src_target)) || (true == Utils::isTargetMultisampled(dst_target))) |
| { |
| continue; |
| } |
| |
| for (GLuint src_frmt_id = 0; src_frmt_id < s_n_internal_formats; ++src_frmt_id) |
| { |
| const GLenum src_format = s_internal_formats[src_frmt_id]; |
| |
| if (src_format == GL_RGB9_E5 && src_target == GL_RENDERBUFFER) |
| { |
| continue; |
| } |
| |
| for (GLuint dst_frmt_id = 0; dst_frmt_id < s_n_internal_formats; ++dst_frmt_id) |
| { |
| const GLenum dst_format = s_internal_formats[dst_frmt_id]; |
| |
| /* Skip not compatible formats */ |
| if (false == Utils::areFormatsCompatible(src_format, dst_format)) |
| { |
| continue; |
| } |
| |
| prepareTestCases(dst_format, dst_target, src_format, src_target); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult FunctionalTest::iterate() |
| { |
| GLubyte* dst_pixels[FUNCTIONAL_TEST_N_LEVELS] = { 0 }; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLubyte* src_pixels[FUNCTIONAL_TEST_N_LEVELS] = { 0 }; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 1); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "PixelStorei"); |
| |
| try |
| { |
| /* Prepare pixels */ |
| prepareDstPxls(test_case.m_dst, dst_pixels); |
| prepareSrcPxls(test_case.m_src, test_case.m_dst.m_internal_format, src_pixels); |
| |
| /* Prepare textures */ |
| m_dst_tex_name = prepareTexture(test_case.m_dst, (const GLubyte**)dst_pixels, m_dst_buf_name); |
| |
| if (GL_RENDERBUFFER == test_case.m_src.m_target) |
| { |
| targetDesc desc = test_case.m_src; |
| desc.m_target = GL_TEXTURE_2D; |
| |
| m_rb_name = prepareTexture(test_case.m_src, (const GLubyte**)src_pixels, m_src_buf_name); |
| m_src_tex_name = prepareTexture(desc, (const GLubyte**)src_pixels, m_src_buf_name); |
| } |
| else |
| { |
| m_src_tex_name = prepareTexture(test_case.m_src, (const GLubyte**)src_pixels, m_src_buf_name); |
| } |
| |
| /* Copy images and verify results */ |
| result = copyAndVerify(test_case, (const GLubyte**)dst_pixels, (const GLubyte**)src_pixels); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| cleanPixels((GLubyte**)dst_pixels); |
| cleanPixels((GLubyte**)src_pixels); |
| throw exc; |
| } |
| |
| /* Free resources */ |
| clean(); |
| cleanPixels((GLubyte**)dst_pixels); |
| cleanPixels((GLubyte**)src_pixels); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failure. " << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Calculate dimmensions of all levels based on size of specific level |
| * |
| * @param target Target of image |
| * @param level Level index |
| * @param width Width of image at <level> |
| * @param height Height of image at <level> |
| * @param out_widths Calcualted widths, array of FUNCTIONAL_TEST_N_LEVELS'th elements |
| * @param out_heights Calculated heights, array of FUNCTIONAL_TEST_N_LEVELS'th elements |
| * @param out_depths Calculated dephts, array of FUNCTIONAL_TEST_N_LEVELS'th elements |
| **/ |
| void FunctionalTest::calculateDimmensions(GLenum target, GLuint level, GLuint width, GLuint height, GLuint* out_widths, |
| GLuint* out_heights, GLuint* out_depths) const |
| { |
| GLuint divide = 100; |
| GLuint factors[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint factor = divide; |
| const bool is_multi_layer = Utils::isTargetMultilayer(target); |
| const GLuint n_layers = (true == is_multi_layer) ? FUNCTIONAL_TEST_N_LAYERS : 1; |
| |
| for (GLint i = (GLint)level; i >= 0; --i) |
| { |
| factors[i] = factor; |
| factor *= 2; |
| } |
| |
| factor = divide / 2; |
| for (GLuint i = level + 1; i < FUNCTIONAL_TEST_N_LEVELS; ++i) |
| { |
| factors[i] = factor; |
| factor /= 2; |
| } |
| |
| for (GLuint i = 0; i < FUNCTIONAL_TEST_N_LEVELS; ++i) |
| { |
| out_widths[i] = width * factors[i] / divide; |
| out_heights[i] = height * factors[i] / divide; |
| |
| if (GL_TEXTURE_3D == target) |
| { |
| out_depths[i] = FUNCTIONAL_TEST_N_LAYERS * factors[i] / divide; |
| } |
| else |
| { |
| out_depths[i] = n_layers; |
| } |
| } |
| } |
| |
| /** Execute copyImageSubData for given test case and verify results |
| * |
| * @param test_case Test case |
| * @param dst_pixels Data of destination image |
| * @param src_pixels Data of source image |
| * |
| * @return true if there is no error and results match expectations, false otherwise |
| **/ |
| bool FunctionalTest::copyAndVerify(const testCase& test_case, const GLubyte** dst_pixels, const GLubyte** src_pixels) |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLuint region_depth = 1; |
| GLuint dst_layer_step = 0; |
| const bool is_dst_multi_layer = Utils::isTargetMultilayer(test_case.m_dst.m_target); |
| const bool is_src_multi_layer = Utils::isTargetMultilayer(test_case.m_src.m_target); |
| bool result = false; |
| GLuint src_layer_step = 0; |
| GLuint n_layers = 1; |
| |
| /* Configure layers */ |
| if ((true == is_dst_multi_layer) || (true == is_src_multi_layer)) |
| { |
| if (is_src_multi_layer == is_dst_multi_layer) |
| { |
| /* Both objects are multilayered, copy all layers at once, verify at once */ |
| region_depth = FUNCTIONAL_TEST_N_LAYERS; |
| } |
| else if (true == is_dst_multi_layer) |
| { |
| /* Destination is multilayered, copy each layer separetly, verify at once */ |
| n_layers = FUNCTIONAL_TEST_N_LAYERS; |
| dst_layer_step = 1; |
| } |
| else |
| { |
| /* Destination is multilayered, copy and verify each layer separetly */ |
| n_layers = FUNCTIONAL_TEST_N_LAYERS; |
| src_layer_step = 1; |
| } |
| } |
| |
| /* Copy and verification */ |
| { |
| GLuint dst_layer = 0; |
| GLuint src_layer = 0; |
| |
| /* For each layer */ |
| for (GLuint layer = 0; layer < n_layers; ++layer) |
| { |
| if (0 == m_rb_name) |
| { |
| gl.copyImageSubData(m_src_tex_name, test_case.m_src.m_target, test_case.m_src.m_level, |
| test_case.m_src_x, test_case.m_src_y, src_layer, m_dst_tex_name, |
| test_case.m_dst.m_target, test_case.m_dst.m_level, test_case.m_dst_x, |
| test_case.m_dst_y, dst_layer, test_case.m_width, test_case.m_height, region_depth); |
| } |
| else /* Copy from src to rb and from rb to dst */ |
| { |
| /* Src and rb shares differs only on target */ |
| gl.copyImageSubData(m_src_tex_name, GL_TEXTURE_2D, test_case.m_src.m_level, test_case.m_src_x, |
| test_case.m_src_y, src_layer, m_rb_name, test_case.m_src.m_target, |
| test_case.m_src.m_level, test_case.m_src_x, test_case.m_src_y, src_layer, |
| test_case.m_width, test_case.m_height, region_depth); |
| |
| gl.copyImageSubData(m_rb_name, test_case.m_src.m_target, test_case.m_src.m_level, test_case.m_src_x, |
| test_case.m_src_y, src_layer, m_dst_tex_name, test_case.m_dst.m_target, |
| test_case.m_dst.m_level, test_case.m_dst_x, test_case.m_dst_y, dst_layer, |
| test_case.m_width, test_case.m_height, region_depth); |
| } |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| |
| if (GL_NO_ERROR == error) |
| { |
| /* Verify copy results */ |
| result = verify(test_case, dst_layer, dst_pixels, src_layer, src_pixels, region_depth); |
| } |
| |
| if ((GL_NO_ERROR != error) || (false == result)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Failure. Targets src: " << glu::getTextureTargetStr(test_case.m_src.m_target) |
| << ", dst: " << glu::getTextureTargetStr(test_case.m_dst.m_target) |
| << ". Levels src: " << test_case.m_src.m_level << ", dst: " << test_case.m_dst.m_level |
| << ". Dimmensions src [" << test_case.m_src.m_width << ", " << test_case.m_src.m_height |
| << "], dst [" << test_case.m_dst.m_width << ", " << test_case.m_dst.m_height << "]. Region [" |
| << test_case.m_width << " x " << test_case.m_height << " x " << region_depth << "] from [" |
| << test_case.m_src_x << ", " << test_case.m_src_y << ", " << src_layer << "] to [" |
| << test_case.m_dst_x << ", " << test_case.m_dst_y << ", " << dst_layer |
| << "]. Format src: " << glu::getInternalFormatParameterStr(test_case.m_src.m_internal_format) |
| << ", dst: " << glu::getInternalFormatParameterStr(test_case.m_dst.m_internal_format) |
| << tcu::TestLog::EndMessage; |
| |
| if (GL_NO_ERROR != error) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Failed due to error: " << glu::getErrorStr(error) |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Copy operation failed"); |
| } |
| |
| return false; |
| } |
| |
| /* Step one layer */ |
| dst_layer += dst_layer_step; |
| src_layer += src_layer_step; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void FunctionalTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| |
| if (0 != m_dst_buf_name) |
| { |
| gl.deleteBuffers(1, &m_dst_buf_name); |
| m_dst_buf_name = 0; |
| } |
| |
| if (0 != m_rb_name) |
| { |
| gl.deleteRenderbuffers(1, &m_rb_name); |
| m_rb_name = 0; |
| } |
| |
| if (0 != m_src_buf_name) |
| { |
| gl.deleteBuffers(1, &m_src_buf_name); |
| m_src_buf_name = 0; |
| } |
| } |
| |
| /** Free memory allocated for images |
| * |
| * @param pixels Array of pointers to image data |
| **/ |
| void FunctionalTest::cleanPixels(GLubyte** pixels) const |
| { |
| for (GLuint i = 0; i < FUNCTIONAL_TEST_N_LEVELS; ++i) |
| { |
| if (0 != pixels[i]) |
| { |
| delete[] pixels[i]; |
| pixels[i] = 0; |
| } |
| } |
| } |
| |
| /** Compare two images |
| * @param left_desc Descriptor of left image |
| * @param left_data Data of left image |
| * @param left_x X of left image |
| * @param left_y Y of left image |
| * @param left_layer Layer of left image |
| * @param left_level Level of left image |
| * @param right_desc Descriptor of right image |
| * @param right_data Data of right image |
| * @param right_x X of right image |
| * @param right_y Y of right image |
| * @param right_layer Layer of right image |
| * @param right_level Level of right image |
| * @param region_width Width of region to compare |
| * @param region_height Height of region to compare |
| * |
| * @return true if images are considered idenctial, false otherwise |
| **/ |
| bool FunctionalTest::compareImages(const targetDesc& left_desc, const GLubyte* left_data, GLuint left_x, GLuint left_y, |
| GLuint left_layer, GLuint left_level, const targetDesc& right_desc, |
| const glw::GLubyte* right_data, GLuint right_x, GLuint right_y, GLuint right_layer, |
| GLuint right_level, GLuint region_width, GLuint region_height) const |
| { |
| /* Get level dimmensions */ |
| GLuint left_heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint left_widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint left_depths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint right_heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint right_widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint right_depths[FUNCTIONAL_TEST_N_LEVELS]; |
| |
| calculateDimmensions(left_desc.m_target, left_desc.m_level, left_desc.m_width, left_desc.m_height, left_widths, |
| left_heights, left_depths); |
| |
| calculateDimmensions(right_desc.m_target, right_desc.m_level, right_desc.m_width, right_desc.m_height, right_widths, |
| right_heights, right_depths); |
| |
| /* Constants */ |
| /* Dimmensions */ |
| const GLuint left_height = left_heights[left_level]; |
| const GLuint left_width = left_widths[left_level]; |
| const GLuint right_height = right_heights[right_level]; |
| const GLuint right_width = right_widths[right_level]; |
| /* Sizes */ |
| const GLuint left_pixel_size = Utils::getPixelSizeForFormat(left_desc.m_internal_format); |
| const GLuint left_line_size = left_pixel_size * left_width; |
| const GLuint left_layer_size = left_line_size * left_height; |
| const GLuint right_pixel_size = Utils::getPixelSizeForFormat(right_desc.m_internal_format); |
| const GLuint right_line_size = right_pixel_size * right_width; |
| const GLuint right_layer_size = right_line_size * right_height; |
| |
| /* Offsets */ |
| const GLuint left_layer_offset = left_layer_size * left_layer; |
| const GLuint left_reg_line_offset = left_line_size * left_y; |
| const GLuint left_reg_pix_offset = left_pixel_size * left_x; |
| const GLuint right_layer_offset = right_layer_size * right_layer; |
| const GLuint right_reg_line_offset = right_line_size * right_y; |
| const GLuint right_reg_pix_offset = right_pixel_size * right_x; |
| |
| /* Pointers */ |
| const GLubyte* left_layer_data = left_data + left_layer_offset; |
| const GLubyte* right_layer_data = right_data + right_layer_offset; |
| |
| /* For each line of region */ |
| for (GLuint y = 0; y < region_height; ++y) |
| { |
| /* Offsets */ |
| const GLuint left_line_offset = left_reg_line_offset + y * left_line_size; |
| const GLuint right_line_offset = right_reg_line_offset + y * right_line_size; |
| |
| /* Pointers */ |
| const GLubyte* left_line_data = left_layer_data + left_line_offset; |
| const GLubyte* right_line_data = right_layer_data + right_line_offset; |
| |
| /* For each pixel of region */ |
| for (GLuint x = 0; x < region_width; ++x) |
| { |
| /* Offsets */ |
| const GLuint left_pixel_offset = left_reg_pix_offset + x * left_pixel_size; |
| const GLuint right_pixel_offset = right_reg_pix_offset + x * right_pixel_size; |
| |
| /* Pointers */ |
| const GLubyte* left_pixel_data = left_line_data + left_pixel_offset; |
| const GLubyte* right_pixel_data = right_line_data + right_pixel_offset; |
| |
| /* Compare */ |
| if (false == Utils::comparePixels(left_pixel_size, left_pixel_data, right_pixel_size, right_pixel_data)) |
| { |
| if (false == Utils::unpackAndComaprePixels(left_desc.m_format, left_desc.m_type, |
| left_desc.m_internal_format, left_pixel_data, |
| right_desc.m_format, right_desc.m_type, |
| right_desc.m_internal_format, right_pixel_data)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Not matching pixels found. Left: [" << x + left_x << ", " |
| << y + left_y << ", " << left_layer << "] lvl:" << left_level |
| << ", off: " << left_pixel_data - left_data |
| << ", data: " << Utils::getPixelString(left_desc.m_internal_format, left_pixel_data) |
| << ". Right: [" << x + right_x << ", " << y + right_y << ", " << right_layer |
| << "] lvl: " << right_level << ", off: " << right_pixel_data - right_data |
| << ", data: " << Utils::getPixelString(right_desc.m_internal_format, right_pixel_data) |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Prepare regions that should not be modified during test case |
| * |
| * @param test_case Test case descriptor |
| * @param dst_level Level of destination image |
| * @param out_regions Number of regions |
| * @param out_n_regions Regions |
| **/ |
| void FunctionalTest::getCleanRegions(const testCase& test_case, GLuint dst_level, GLuint out_regions[4][4], |
| GLuint& out_n_regions) const |
| { |
| GLuint dst_heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint dst_widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint dst_depths[FUNCTIONAL_TEST_N_LEVELS]; |
| |
| out_n_regions = 0; |
| |
| calculateDimmensions(test_case.m_dst.m_target, dst_level, test_case.m_dst.m_width, test_case.m_dst.m_height, |
| dst_widths, dst_heights, dst_depths); |
| |
| /* Constants */ |
| /* Copied region */ |
| const GLuint reg_x = test_case.m_dst_x; |
| const GLuint reg_y = test_case.m_dst_y; |
| const GLuint reg_w = test_case.m_width; |
| const GLuint reg_h = test_case.m_height; |
| const GLuint reg_r = reg_x + reg_w; |
| const GLuint reg_t = reg_y + reg_h; |
| |
| /* Image */ |
| const GLuint img_w = dst_widths[dst_level]; |
| const GLuint img_h = dst_heights[dst_level]; |
| |
| /* Bottom row */ |
| if (0 != reg_y) |
| { |
| out_regions[out_n_regions][0] = 0; |
| out_regions[out_n_regions][1] = 0; |
| out_regions[out_n_regions][2] = img_w; |
| out_regions[out_n_regions][3] = reg_y; |
| out_n_regions += 1; |
| } |
| |
| /* Left edge */ |
| if (0 != reg_x) |
| { |
| out_regions[out_n_regions][0] = 0; |
| out_regions[out_n_regions][1] = reg_y; |
| out_regions[out_n_regions][2] = reg_x; |
| out_regions[out_n_regions][3] = reg_h; |
| out_n_regions += 1; |
| } |
| |
| /* Right edge */ |
| if (img_w != reg_r) |
| { |
| out_regions[out_n_regions][0] = reg_r; |
| out_regions[out_n_regions][1] = reg_y; |
| out_regions[out_n_regions][2] = img_w - reg_r; |
| out_regions[out_n_regions][3] = reg_h; |
| out_n_regions += 1; |
| } |
| |
| /* Top row */ |
| if (img_h != reg_t) |
| { |
| out_regions[out_n_regions][0] = 0; |
| out_regions[out_n_regions][1] = reg_t; |
| out_regions[out_n_regions][2] = img_w; |
| out_regions[out_n_regions][3] = img_h - reg_t; |
| out_n_regions += 1; |
| } |
| } |
| |
| /** Get pixel data for image |
| * |
| * @param name Name of image |
| * @param desc Descriptor of image |
| * @param level Level to capture |
| * @param out_pixels Pixels |
| **/ |
| void FunctionalTest::getPixels(GLuint name, const targetDesc& desc, GLuint level, GLubyte* out_pixels) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindTexture(desc.m_target, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.getTexImage(desc.m_target, level, desc.m_format, desc.m_type, out_pixels); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage"); |
| |
| gl.bindTexture(desc.m_target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| } |
| |
| /** Prepare data for destination image |
| * |
| * @param desc Descriptor |
| * @param out_pixels Array of pointer to image data |
| **/ |
| void FunctionalTest::prepareDstPxls(const FunctionalTest::targetDesc& desc, GLubyte** out_pixels) const |
| { |
| const GLenum internal_format = desc.m_internal_format; |
| const bool is_multi_level = Utils::isTargetMultilevel(desc.m_target); |
| GLuint n_levels = 1; |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(desc.m_internal_format); |
| const GLenum type = desc.m_type; |
| |
| /* Configure levels */ |
| if (true == is_multi_level) |
| { |
| n_levels = FUNCTIONAL_TEST_N_LEVELS; |
| } |
| |
| /* Calculate dimmensions */ |
| GLuint heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint depths[FUNCTIONAL_TEST_N_LEVELS]; |
| |
| calculateDimmensions(desc.m_target, desc.m_level, desc.m_width, desc.m_height, widths, heights, depths); |
| |
| /* Prepare storage */ |
| for (GLuint i = 0; i < n_levels; ++i) |
| { |
| const GLuint req_memory_per_layer = pixel_size * widths[i] * heights[i]; |
| const GLuint req_memory_for_level = req_memory_per_layer * depths[i]; |
| |
| out_pixels[i] = new GLubyte[req_memory_for_level]; |
| |
| if (0 == out_pixels[i]) |
| { |
| TCU_FAIL("Memory allocation failed"); |
| } |
| |
| memset(out_pixels[i], 0, req_memory_for_level); |
| } |
| |
| /* Fill pixels */ |
| for (GLuint i = 0; i < n_levels; ++i) |
| { |
| const GLuint n_layers = depths[i]; |
| const GLuint n_pixels = widths[i] * heights[i]; |
| GLubyte* ptr = (GLubyte*)out_pixels[i]; |
| |
| for (GLuint j = 0; j < n_pixels * n_layers; ++j) |
| { |
| GLubyte* pixel_data = ptr + j * pixel_size; |
| |
| Utils::packPixel(internal_format, type, 1.0, 1.0, 1.0, 1.0, pixel_data); |
| } |
| } |
| } |
| |
| /** Prepare data for source image |
| * |
| * @param desc Descriptor |
| * @param dst_internal_format Internal format of destination image |
| * @param out_pixels Array of pointer to image data |
| **/ |
| void FunctionalTest::prepareSrcPxls(const FunctionalTest::targetDesc& desc, GLenum /* dst_internal_format */, |
| GLubyte** out_pixels) const |
| { |
| const GLenum internal_format = desc.m_internal_format; |
| const bool is_multi_level = Utils::isTargetMultilevel(desc.m_target); |
| GLuint n_levels = 1; |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(desc.m_internal_format); |
| const GLenum type = desc.m_type; |
| |
| /* Configure levels */ |
| if (true == is_multi_level) |
| { |
| n_levels = FUNCTIONAL_TEST_N_LEVELS; |
| } |
| |
| /* Calculate dimmensions */ |
| GLuint heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint depths[FUNCTIONAL_TEST_N_LEVELS]; |
| |
| calculateDimmensions(desc.m_target, desc.m_level, desc.m_width, desc.m_height, widths, heights, depths); |
| |
| /* Prepare storage */ |
| for (GLuint i = 0; i < n_levels; ++i) |
| { |
| const GLuint req_memory_per_layer = pixel_size * widths[i] * heights[i]; |
| const GLuint req_memory_for_level = req_memory_per_layer * depths[i]; |
| |
| out_pixels[i] = new GLubyte[req_memory_for_level]; |
| |
| if (0 == out_pixels[i]) |
| { |
| TCU_FAIL("Memory allocation failed"); |
| } |
| |
| memset(out_pixels[i], 0, req_memory_for_level); |
| } |
| |
| for (GLuint lvl = 0; lvl < n_levels; ++lvl) |
| { |
| const GLuint n_layers = depths[lvl]; |
| const GLuint line_size = pixel_size * widths[lvl]; |
| const GLuint req_memory_per_layer = line_size * heights[lvl]; |
| GLubyte* level = (GLubyte*)out_pixels[lvl]; |
| |
| for (GLuint lay = 0; lay < n_layers; ++lay) |
| { |
| const GLuint layer_offset = lay * req_memory_per_layer; |
| |
| GLubyte* layer = ((GLubyte*)level) + layer_offset; |
| |
| for (GLuint y = 0; y < heights[lvl]; ++y) |
| { |
| const GLuint line_offset = line_size * y; |
| |
| GLubyte* line = layer + line_offset; |
| |
| for (GLuint x = 0; x < widths[lvl]; ++x) |
| { |
| const GLuint pixel_offset = x * pixel_size; |
| |
| GLubyte* pixel = line + pixel_offset; |
| |
| /* 255 is max ubyte. 1/15.9375 = 16/255 */ |
| const GLdouble red = ((GLdouble)x) / 255.0 + (((GLdouble)y) / 15.9375); |
| const GLdouble green = ((GLdouble)lay) / 255.0 + (((GLdouble)lvl) / 15.9375); |
| const GLdouble blue = 0.125; |
| const GLdouble alpha = 1.0; /* This value has special meaning for some internal_formats */ |
| |
| Utils::packPixel(internal_format, type, red, green, blue, alpha, pixel); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Prepare test cases for given targets and internal formats |
| * |
| * @param dst_internal_format Internal format of destination image |
| * @param dst_target Target of destination image |
| * @param src_internal_format Internal format of source image |
| * @param src_target Target of source image |
| **/ |
| void FunctionalTest::prepareTestCases(GLenum dst_internal_format, GLenum dst_target, GLenum src_internal_format, |
| GLenum src_target) |
| { |
| static const GLuint image_dimmensions[] = { |
| 7, |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_IMG_DIM |
| 8, |
| 9, |
| 10, |
| 11, |
| 12, |
| 13, |
| 14, |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_IMG_DIM */ |
| 15 |
| }; |
| |
| static const GLuint region_dimmensions[] = { |
| 1, |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_DIM |
| 2, |
| 3, |
| 4, |
| 5, |
| 6, |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_DIM */ |
| 7 |
| }; |
| |
| static const GLuint n_image_dimmensions = sizeof(image_dimmensions) / sizeof(image_dimmensions[0]); |
| static const GLuint n_region_dimmensions = sizeof(region_dimmensions) / sizeof(region_dimmensions[0]); |
| |
| const bool is_dst_multi_level = Utils::isTargetMultilevel(dst_target); |
| const bool is_src_multi_level = Utils::isTargetMultilevel(src_target); |
| const GLenum dst_format = Utils::getFormat(dst_internal_format); |
| const GLuint dst_n_levels = (true == is_dst_multi_level) ? FUNCTIONAL_TEST_N_LEVELS : 1; |
| const GLenum dst_type = Utils::getType(dst_internal_format); |
| const GLenum src_format = Utils::getFormat(src_internal_format); |
| const GLuint src_n_levels = (true == is_src_multi_level) ? FUNCTIONAL_TEST_N_LEVELS : 1; |
| const GLenum src_type = Utils::getType(src_internal_format); |
| |
| for (GLuint src_level = 0; src_level < src_n_levels; ++src_level) |
| { |
| for (GLuint dst_level = 0; dst_level < dst_n_levels; ++dst_level) |
| { |
| for (GLuint src_img_dim_id = 0; src_img_dim_id < n_image_dimmensions; ++src_img_dim_id) |
| { |
| const GLuint src_image_dimmension = image_dimmensions[src_img_dim_id]; |
| |
| for (GLuint dst_img_dim_id = 0; dst_img_dim_id < n_image_dimmensions; ++dst_img_dim_id) |
| { |
| const GLuint dst_image_dimmension = image_dimmensions[dst_img_dim_id]; |
| |
| for (GLuint reg_dim_id = 0; reg_dim_id < n_region_dimmensions; ++reg_dim_id) |
| { |
| const GLuint region_dimmension = region_dimmensions[reg_dim_id]; |
| GLuint dst_coord[3] = { 0, 0, 0 }; |
| const GLuint dst_dim_diff = dst_image_dimmension - region_dimmension; |
| GLuint n_dst_coords = 1; |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS |
| GLuint n_src_coords = 1; |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS */ |
| GLuint src_coord[3] = { 0, 0, 0 }; |
| const GLuint src_dim_diff = src_image_dimmension - region_dimmension; |
| |
| /* Calculate coords */ |
| if (1 == dst_dim_diff) |
| { |
| dst_coord[1] = 1; |
| n_dst_coords = 2; |
| } |
| else if (1 < dst_dim_diff) |
| { |
| dst_coord[1] = dst_dim_diff / 2; |
| dst_coord[2] = dst_dim_diff; |
| n_dst_coords = 3; |
| } |
| |
| if (1 == src_dim_diff) |
| { |
| src_coord[1] = 1; |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS |
| n_src_coords = 2; |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS */ |
| } |
| else if (1 < src_dim_diff) |
| { |
| src_coord[1] = src_dim_diff / 2; |
| src_coord[2] = src_dim_diff; |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS |
| n_src_coords = 3; |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS */ |
| } |
| |
| testCase test_case = { |
| { /* m_dst */ |
| dst_target, dst_image_dimmension, /* width */ |
| dst_image_dimmension, /* height */ |
| dst_level, dst_internal_format, dst_format, dst_type }, |
| 0, /* dst_x */ |
| 0, /* dst_y */ |
| { /* m_src */ |
| src_target, src_image_dimmension, /* width */ |
| src_image_dimmension, /* height */ |
| src_level, src_internal_format, src_format, src_type }, |
| 0, /* src_x */ |
| 0, /* src_y */ |
| region_dimmension, /* width */ |
| region_dimmension, /* height */ |
| }; |
| |
| #if COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS |
| for (GLuint src_x = 0; src_x < n_src_coords; ++src_x) |
| { |
| for (GLuint src_y = 0; src_y < n_src_coords; ++src_y) |
| { |
| for (GLuint dst_x = 0; dst_x < n_dst_coords; ++dst_x) |
| { |
| for (GLuint dst_y = 0; dst_y < n_dst_coords; ++dst_y) |
| { |
| test_case.m_dst_x = dst_coord[dst_x]; |
| test_case.m_dst_y = dst_coord[dst_y]; |
| test_case.m_src_x = src_coord[src_x]; |
| test_case.m_src_y = src_coord[src_y]; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| #else /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS */ |
| test_case.m_dst_x = dst_coord[n_dst_coords - 1]; |
| test_case.m_dst_y = dst_coord[n_dst_coords - 1]; |
| test_case.m_src_x = src_coord[0]; |
| test_case.m_src_y = src_coord[0]; |
| |
| m_test_cases.push_back(test_case); |
| #endif /* COPY_IMAGE_FUNCTIONAL_TEST_ENABLE_ALL_REG_POS */ |
| |
| /* Whole image, for non 7x7 */ |
| if ((dst_image_dimmension == src_image_dimmension) && |
| (image_dimmensions[0] != dst_image_dimmension)) |
| { |
| test_case.m_dst_x = 0; |
| test_case.m_dst_y = 0; |
| test_case.m_src_x = 0; |
| test_case.m_src_y = 0; |
| test_case.m_width = dst_image_dimmension; |
| test_case.m_height = dst_image_dimmension; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** Prepare texture |
| * |
| * @param desc Descriptor |
| * @param pixels Image data |
| * @param out_buf_id Id of buffer used by texture buffer |
| * |
| * @return Name of iamge |
| **/ |
| GLuint FunctionalTest::prepareTexture(const targetDesc& desc, const GLubyte** pixels, GLuint& out_buf_id) |
| { |
| GLuint name = Utils::generateTexture(m_context, desc.m_target); |
| |
| if (false == Utils::isTargetMultilevel(desc.m_target)) |
| { |
| Utils::prepareTexture(m_context, name, desc.m_target, desc.m_internal_format, desc.m_format, desc.m_type, |
| 0 /* level */, desc.m_width, desc.m_height, |
| FUNCTIONAL_TEST_N_LAYERS /* depth - 12 for multilayered, 1D and 2D will ignore that */, |
| pixels[0], out_buf_id); |
| |
| Utils::makeTextureComplete(m_context, desc.m_target, name, 0 /* base */, 0 /* max */); |
| } |
| else |
| { |
| /* Calculate dimmensions */ |
| GLuint heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint depths[FUNCTIONAL_TEST_N_LEVELS]; |
| |
| calculateDimmensions(desc.m_target, desc.m_level, desc.m_width, desc.m_height, widths, heights, depths); |
| |
| for (GLuint level = 0; level < FUNCTIONAL_TEST_N_LEVELS; ++level) |
| { |
| Utils::prepareTexture(m_context, name, desc.m_target, desc.m_internal_format, desc.m_format, desc.m_type, |
| level, widths[level], heights[level], depths[level], pixels[level], out_buf_id); |
| |
| Utils::makeTextureComplete(m_context, desc.m_target, name, 0 /* base */, 2 /* max */); |
| } |
| } |
| |
| return name; |
| } |
| |
| /** Verify copy operation |
| * |
| * @param test_case Test case |
| * @param dst_layer First layer modified by copy |
| * @param dst_pixels Origiranl data of destination image |
| * @param src_layer First layer read by copy |
| * @param src_pixels Original data of source image |
| * @param depth Number of copied layers |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool FunctionalTest::verify(const testCase& test_case, GLuint dst_layer, const GLubyte** dst_pixels, GLuint src_layer, |
| const GLubyte** src_pixels, GLuint depth) |
| { |
| const bool is_dst_multi_level = Utils::isTargetMultilevel(test_case.m_dst.m_target); |
| const bool is_src_multi_level = Utils::isTargetMultilevel(test_case.m_src.m_target); |
| const GLuint dst_level = test_case.m_dst.m_level; |
| std::vector<GLubyte> dst_level_data; |
| const GLuint dst_pixel_size = Utils::getPixelSizeForFormat(test_case.m_dst.m_internal_format); |
| targetDesc src_desc = test_case.m_src; |
| const GLuint src_level = src_desc.m_level; |
| std::vector<GLubyte> src_level_data; |
| const GLuint src_pixel_size = Utils::getPixelSizeForFormat(src_desc.m_internal_format); |
| |
| if (0 != m_rb_name) |
| { |
| src_desc.m_target = GL_TEXTURE_2D; |
| } |
| |
| /* Calculate storage requirements */ |
| GLuint dst_req_mem_per_layer[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint dst_heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint dst_widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint dst_depths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint src_req_mem_per_layer[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint src_heights[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint src_widths[FUNCTIONAL_TEST_N_LEVELS]; |
| GLuint src_depths[FUNCTIONAL_TEST_N_LEVELS]; |
| |
| calculateDimmensions(test_case.m_dst.m_target, dst_level, test_case.m_dst.m_width, test_case.m_dst.m_height, |
| dst_widths, dst_heights, dst_depths); |
| |
| calculateDimmensions(src_desc.m_target, src_level, src_desc.m_width, src_desc.m_height, src_widths, src_heights, |
| src_depths); |
| |
| for (GLuint i = 0; i < FUNCTIONAL_TEST_N_LEVELS; ++i) |
| { |
| dst_req_mem_per_layer[i] = dst_widths[i] * dst_heights[i] * dst_pixel_size; |
| src_req_mem_per_layer[i] = src_widths[i] * src_heights[i] * src_pixel_size; |
| } |
| |
| /* Prepare storage, use 0 level as it is the biggest one */ |
| dst_level_data.resize(dst_req_mem_per_layer[0] * dst_depths[0]); |
| src_level_data.resize(src_req_mem_per_layer[0] * src_depths[0]); |
| |
| /* Verification of contents |
| * - source image - expect no modification |
| * - destination image, mipmap before and after dst_level - expect no modification |
| * - destination image, mipmap at dst_level: |
| * * layers after dst_layer + depth - expect no modification |
| * * layers <0, dst_layer + depth> - expect that contents at selected region were copied |
| */ |
| |
| /* Check if source image was not modified */ |
| { |
| const GLuint n_levels = (true == is_src_multi_level) ? FUNCTIONAL_TEST_N_LEVELS : 1; |
| |
| for (GLuint level = 0; level < n_levels; ++level) |
| { |
| getPixels(m_src_tex_name, src_desc, level, &src_level_data[0]); |
| |
| for (GLuint layer = 0; layer < src_depths[level]; ++layer) |
| { |
| if (false == compareImages(src_desc, src_pixels[level], 0, 0, layer, level, src_desc, |
| &src_level_data[0], 0, 0, layer, level, src_widths[level], |
| src_heights[level])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "CopyImageSubData modified contents of source image. Original data: left." |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| } |
| |
| /* Check if contents of destination at levels != dst_level were not modified */ |
| { |
| const GLuint n_levels = (true == is_dst_multi_level) ? FUNCTIONAL_TEST_N_LEVELS : 1; |
| |
| for (GLuint level = 0; level < n_levels; ++level) |
| { |
| if (dst_level == level) |
| { |
| continue; |
| } |
| |
| getPixels(m_dst_tex_name, test_case.m_dst, level, &dst_level_data[0]); |
| |
| for (GLuint layer = 0; layer < dst_depths[level]; ++layer) |
| { |
| if (false == compareImages(test_case.m_dst, dst_pixels[level], 0, 0, layer, level, test_case.m_dst, |
| &dst_level_data[0], 0, 0, layer, level, dst_widths[level], |
| dst_heights[level])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "CopyImageSubData modified contents of wrong mipmap level. Original data: left." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| } |
| } |
| |
| /* Check contents of modified level */ |
| { |
| getPixels(m_dst_tex_name, test_case.m_dst, dst_level, &dst_level_data[0]); |
| |
| /* Check anything after dst_layer + depth */ |
| { |
| for (GLuint layer = dst_layer + depth; layer < dst_depths[dst_level]; ++layer) |
| { |
| if (false == compareImages(test_case.m_dst, dst_pixels[dst_level], 0, 0, layer, dst_level, |
| test_case.m_dst, &dst_level_data[0], 0, 0, layer, dst_level, |
| dst_widths[dst_level], dst_heights[dst_level])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "CopyImageSubData modified contents of wrong layer. Original data: left." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| } |
| |
| /* Check modified layers */ |
| for (GLuint layer = 0; layer < depth; ++layer) |
| { |
| /* Check contents outside of copied region */ |
| { |
| GLuint n_regions = 0; |
| GLuint regions[4][4] = { { 0 } }; |
| |
| getCleanRegions(test_case, dst_level, regions, n_regions); |
| |
| for (GLuint region = 0; region < n_regions; ++region) |
| { |
| const GLuint x = regions[region][0]; |
| const GLuint y = regions[region][1]; |
| const GLuint w = regions[region][2]; |
| const GLuint h = regions[region][3]; |
| |
| if (false == compareImages(test_case.m_dst, dst_pixels[dst_level], x, y, layer + dst_layer, |
| dst_level, test_case.m_dst, &dst_level_data[0], x, y, layer + dst_layer, |
| dst_level, w, h)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "CopyImageSubData modified contents outside of copied region. Original data: left." |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| |
| /* Check contents of copied region */ |
| if (false == compareImages(test_case.m_dst, &dst_level_data[0], test_case.m_dst_x, test_case.m_dst_y, |
| layer + dst_layer, dst_level, src_desc, src_pixels[src_level], test_case.m_src_x, |
| test_case.m_src_y, layer + src_layer, src_level, test_case.m_width, |
| test_case.m_height)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "CopyImageSubData stored invalid data in copied region. Destination data: left." |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /* SmokeTest */ |
| /* Constants */ |
| const GLuint SmokeTest::m_width = 16; |
| const GLuint SmokeTest::m_height = 16; |
| const GLuint SmokeTest::m_depth = 1; |
| |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| SmokeTest::SmokeTest(deqp::Context& context) |
| : TestCase(context, "smoke_test", "Test tries all formats and targets") |
| , m_dst_buf_name(0) |
| , m_dst_tex_name(0) |
| , m_rb_name(0) |
| , m_src_buf_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| /* Iterate over valid targets */ |
| for (GLuint tgt_id = 0; tgt_id < s_n_valid_targets; ++tgt_id) |
| { |
| const GLenum target = s_valid_targets[tgt_id]; |
| |
| if (true == Utils::isTargetMultisampled(target)) |
| { |
| continue; |
| } |
| |
| const testCase test_case = { target, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* Iterate over internal formats */ |
| for (GLuint fmt_id = 0; fmt_id < s_n_internal_formats; ++fmt_id) |
| { |
| const GLenum internal_format = s_internal_formats[fmt_id]; |
| const GLenum format = Utils::getFormat(internal_format); |
| const GLenum type = Utils::getType(internal_format); |
| |
| const testCase test_case = { GL_TEXTURE_2D, internal_format, format, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void SmokeTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| |
| if (0 != m_dst_buf_name) |
| { |
| gl.deleteBuffers(1, &m_dst_buf_name); |
| m_dst_buf_name = 0; |
| } |
| |
| if (0 != m_rb_name) |
| { |
| gl.deleteRenderbuffers(1, &m_rb_name); |
| m_rb_name = 0; |
| } |
| |
| if (0 != m_src_buf_name) |
| { |
| gl.deleteBuffers(1, &m_src_buf_name); |
| m_src_buf_name = 0; |
| } |
| } |
| |
| /** Free memory allocated for images |
| * |
| * @param pixels Pointers to image data |
| **/ |
| void SmokeTest::cleanPixels(GLubyte*& pixels) const |
| { |
| if (0 == pixels) |
| { |
| return; |
| } |
| |
| delete[] pixels; |
| pixels = 0; |
| } |
| |
| /** Compare two images |
| * @param test_case Test case descriptor |
| * @param left_data Data of left image |
| * @param right_data Data of right image |
| * |
| * @return true if images are considered idenctial, false otherwise |
| **/ |
| bool SmokeTest::compareImages(const testCase& test_case, const GLubyte* left_data, const GLubyte* right_data) const |
| { |
| /* Constants */ |
| /* Sizes */ |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(test_case.m_internal_format); |
| const GLuint line_size = pixel_size * m_width; |
| |
| GLuint height = m_height; |
| |
| if ((GL_TEXTURE_1D == test_case.m_target) || (GL_TEXTURE_1D_ARRAY == test_case.m_target)) |
| { |
| height = 1; |
| } |
| |
| /* For each line */ |
| for (GLuint y = 0; y < height; ++y) |
| { |
| /* Offsets */ |
| const GLuint line_offset = y * line_size; |
| |
| /* Pointers */ |
| const GLubyte* left_line_data = left_data + line_offset; |
| const GLubyte* right_line_data = right_data + line_offset; |
| |
| /* For each pixel of region */ |
| for (GLuint x = 0; x < m_width; ++x) |
| { |
| /* Offsets */ |
| const GLuint pixel_offset = x * pixel_size; |
| |
| /* Pointers */ |
| const GLubyte* left_pixel_data = left_line_data + pixel_offset; |
| const GLubyte* right_pixel_data = right_line_data + pixel_offset; |
| |
| /* Compare */ |
| if (false == Utils::comparePixels(pixel_size, left_pixel_data, pixel_size, right_pixel_data)) |
| { |
| if (false == Utils::unpackAndComaprePixels( |
| test_case.m_format, test_case.m_type, test_case.m_internal_format, left_pixel_data, |
| test_case.m_format, test_case.m_type, test_case.m_internal_format, right_pixel_data)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Not matching pixels found. " |
| << "[" << x << ", " << y << "], off: " << left_pixel_data - left_data |
| << ". Data left: " << Utils::getPixelString(test_case.m_internal_format, left_pixel_data) |
| << ", right: " << Utils::getPixelString(test_case.m_internal_format, right_pixel_data) |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Execute copyImageSubData for given test case and verify results |
| * |
| * @param test_case Test case |
| * @param src_pixels Data of source image |
| * |
| * @return true if there is no error and results match expectations, false otherwise |
| **/ |
| bool SmokeTest::copyAndVerify(const testCase& test_case, const GLubyte* src_pixels) |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = false; |
| |
| /* Copy and verification */ |
| { |
| if (0 == m_rb_name) |
| { |
| GLuint height = m_height; |
| |
| if ((GL_TEXTURE_1D == test_case.m_target) || (GL_TEXTURE_1D_ARRAY == test_case.m_target)) |
| { |
| height = 1; |
| } |
| |
| gl.copyImageSubData(m_src_tex_name, test_case.m_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, m_width, height, m_depth); |
| } |
| else /* Copy from src to rb and from rb to dst */ |
| { |
| /* Src and rb shares differs only on target */ |
| gl.copyImageSubData(m_src_tex_name, GL_TEXTURE_2D, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_rb_name, test_case.m_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, m_width, m_height, m_depth); |
| |
| gl.copyImageSubData(m_rb_name, test_case.m_target, 0 /* dstLevel */, 0 /* dstX */, 0 /* dstY */, |
| 0 /* dstZ */, m_dst_tex_name, GL_TEXTURE_2D, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, m_width, m_height, m_depth); |
| } |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| |
| if (GL_NO_ERROR == error) |
| { |
| /* Verify copy results */ |
| result = verify(test_case, src_pixels); |
| } |
| |
| if ((GL_NO_ERROR != error) || (false == result)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Target: " << glu::getTextureTargetStr(test_case.m_target) |
| << ". Format: " << glu::getInternalFormatParameterStr(test_case.m_internal_format) |
| << tcu::TestLog::EndMessage; |
| |
| if (GL_NO_ERROR != error) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Failed due to error: " << glu::getErrorStr(error) |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Copy operation failed"); |
| } |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Get pixel data for image |
| * |
| * @param name Name of image |
| * @param test_case Test case descriptor |
| * @param out_pixels Pixels |
| **/ |
| void SmokeTest::getPixels(GLuint name, const SmokeTest::testCase& test_case, GLubyte* out_pixels) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLenum tgt_bind = test_case.m_target; |
| GLenum tgt_get = test_case.m_target; |
| |
| if (GL_RENDERBUFFER == test_case.m_target) |
| { |
| tgt_bind = GL_TEXTURE_2D; |
| tgt_get = GL_TEXTURE_2D; |
| } |
| else if (GL_TEXTURE_CUBE_MAP == test_case.m_target) |
| { |
| tgt_get = GL_TEXTURE_CUBE_MAP_POSITIVE_X; |
| } |
| |
| gl.bindTexture(tgt_bind, name); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| |
| gl.getTexImage(tgt_get, 0 /* level */, test_case.m_format, test_case.m_type, out_pixels); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage"); |
| |
| gl.bindTexture(tgt_bind, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult SmokeTest::iterate() |
| { |
| GLubyte* dst_pixels = 0; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLubyte* src_pixels = 0; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 1); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "PixelStorei"); |
| |
| try |
| { |
| /* Prepare pixels */ |
| prepareDstPxls(test_case, dst_pixels); |
| prepareSrcPxls(test_case, src_pixels); |
| |
| /* Prepare textures */ |
| if (GL_RENDERBUFFER == test_case.m_target) |
| { |
| testCase desc = test_case; |
| GLuint ignored = 0; |
| |
| desc.m_target = GL_TEXTURE_2D; |
| |
| m_rb_name = prepareTexture(test_case, 0 /* pixels */, ignored /* buffer name */); |
| m_dst_tex_name = prepareTexture(desc, dst_pixels, m_dst_buf_name); |
| m_src_tex_name = prepareTexture(desc, src_pixels, m_src_buf_name); |
| } |
| else |
| { |
| m_dst_tex_name = prepareTexture(test_case, dst_pixels, m_dst_buf_name); |
| m_src_tex_name = prepareTexture(test_case, src_pixels, m_src_buf_name); |
| } |
| |
| /* Copy images and verify results */ |
| result = copyAndVerify(test_case, src_pixels); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| cleanPixels(dst_pixels); |
| cleanPixels(src_pixels); |
| throw exc; |
| } |
| |
| /* Free resources */ |
| clean(); |
| cleanPixels(dst_pixels); |
| cleanPixels(src_pixels); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failure. " << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Prepare data for destination image |
| * |
| * @param test_case Test case descriptor |
| * @param out_pixels Pointer to image data |
| **/ |
| void SmokeTest::prepareDstPxls(const SmokeTest::testCase& test_case, GLubyte*& out_pixels) const |
| { |
| static const GLuint n_pixels_per_layer = m_width * m_height; |
| |
| const GLenum internal_format = test_case.m_internal_format; |
| const GLuint n_layers = (GL_TEXTURE_CUBE_MAP_ARRAY != test_case.m_target) ? m_depth : 6; |
| const GLuint n_pixels = n_pixels_per_layer * n_layers; |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(internal_format); |
| const GLuint req_memory = pixel_size * n_pixels; |
| const GLenum type = test_case.m_type; |
| |
| /* Prepare storage */ |
| out_pixels = new GLubyte[req_memory]; |
| |
| if (0 == out_pixels) |
| { |
| TCU_FAIL("Memory allocation failed"); |
| } |
| |
| memset(out_pixels, 0, req_memory); |
| |
| /* Fill pixels */ |
| for (GLuint j = 0; j < n_pixels; ++j) |
| { |
| GLubyte* pixel_data = out_pixels + j * pixel_size; |
| |
| Utils::packPixel(internal_format, type, 1.0, 1.0, 1.0, 1.0, pixel_data); |
| } |
| } |
| |
| /** Prepare data for source image |
| * |
| * @param test_case Test case descriptor |
| * @param out_pixels Pointer to image data |
| **/ |
| void SmokeTest::prepareSrcPxls(const SmokeTest::testCase& test_case, GLubyte*& out_pixels) const |
| { |
| static const GLuint n_pixels_per_layer = m_width * m_height; |
| |
| const GLenum internal_format = test_case.m_internal_format; |
| const GLuint n_layers = (GL_TEXTURE_CUBE_MAP_ARRAY != test_case.m_target) ? m_depth : 6; |
| const GLuint n_pixels = n_pixels_per_layer * n_layers; |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(internal_format); |
| const GLuint layer_size = pixel_size * n_pixels_per_layer; |
| const GLuint line_size = pixel_size * m_width; |
| const GLuint req_memory = pixel_size * n_pixels; |
| const GLenum type = test_case.m_type; |
| |
| /* Prepare storage */ |
| out_pixels = new GLubyte[req_memory]; |
| |
| if (0 == out_pixels) |
| { |
| TCU_FAIL("Memory allocation failed"); |
| } |
| |
| memset(out_pixels, 0, req_memory); |
| |
| /* Fill pixels */ |
| for (GLuint layer = 0; layer < n_layers; ++layer) |
| { |
| const GLuint layer_offset = layer * layer_size; |
| |
| GLubyte* layer_data = out_pixels + layer_offset; |
| |
| for (GLuint y = 0; y < m_height; ++y) |
| { |
| const GLuint line_offset = line_size * y; |
| |
| GLubyte* line_data = layer_data + line_offset; |
| |
| for (GLuint x = 0; x < m_width; ++x) |
| { |
| const GLuint pixel_offset = x * pixel_size; |
| |
| GLubyte* pixel_data = line_data + pixel_offset; |
| |
| /* 255 is max ubyte. 1/15.9375 = 16/255 */ |
| const GLdouble red = ((GLdouble)x) / 255.0 + (((GLdouble)y) / 15.9375); |
| const GLdouble green = ((GLdouble)layer) / 255.0 + (1.0 / 15.9375); |
| const GLdouble blue = 0.125; |
| const GLdouble alpha = 1.0; /* This value has special meaning for some internal_formats */ |
| |
| Utils::packPixel(internal_format, type, red, green, blue, alpha, pixel_data); |
| } |
| } |
| } |
| } |
| |
| /** Prepare texture |
| * |
| * @param desc Descriptor |
| * @param pixels Image data |
| * @param out_buf_id Id of buffer used by texture buffer |
| * |
| * @return Name of iamge |
| **/ |
| GLuint SmokeTest::prepareTexture(const testCase& test_case, const GLubyte* pixels, GLuint& out_buf_id) |
| { |
| const GLuint n_layers = (GL_TEXTURE_CUBE_MAP_ARRAY != test_case.m_target) ? m_depth : 6; |
| GLuint name = Utils::generateTexture(m_context, test_case.m_target); |
| |
| Utils::prepareTexture(m_context, name, test_case.m_target, test_case.m_internal_format, test_case.m_format, |
| test_case.m_type, 0 /* level */, m_width, m_height, n_layers, pixels, out_buf_id); |
| |
| Utils::makeTextureComplete(m_context, test_case.m_target, name, 0 /* base */, 0 /* max */); |
| |
| return name; |
| } |
| |
| /** Verify copy operation |
| * |
| * @param test_case Test case |
| * @param src_pixels Original data of source image |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool SmokeTest::verify(const testCase& test_case, const GLubyte* src_pixels) |
| { |
| std::vector<GLubyte> dst_data; |
| const GLuint n_layers = (GL_TEXTURE_CUBE_MAP_ARRAY != test_case.m_target) ? m_depth : 6; |
| const GLuint pixel_size = Utils::getPixelSizeForFormat(test_case.m_internal_format); |
| const GLuint line_size = pixel_size * m_width; |
| const GLuint req_memory = line_size * m_height * n_layers; |
| std::vector<GLubyte> src_data; |
| |
| /* Prepare storage */ |
| dst_data.resize(req_memory); |
| src_data.resize(req_memory); |
| |
| /* Check if source image was not modified */ |
| { |
| getPixels(m_src_tex_name, test_case, &src_data[0]); |
| |
| if (false == compareImages(test_case, src_pixels, &src_data[0])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "CopyImageSubData modified contents of source image. Original data: left." |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| /* Check contents of destination image */ |
| { |
| getPixels(m_dst_tex_name, test_case, &dst_data[0]); |
| |
| if (false == compareImages(test_case, src_pixels, &dst_data[0])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "CopyImageSubData stored invalid contents in destination image. Source data: left." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /* InvalidTargetTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| InvalidTargetTest::InvalidTargetTest(deqp::Context& context) |
| : TestCase(context, "invalid_target", |
| "Test verifies if INVALID_ENUM is generated when invalid target is provided to CopyImageSubData") |
| , m_dst_buf_name(0) |
| , m_dst_tex_name(0) |
| , m_src_buf_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| |
| /* Valid source, valid dst */ |
| for (GLuint src = 0; src < s_n_valid_targets; ++src) |
| { |
| for (GLuint dst = 0; dst < s_n_valid_targets; ++dst) |
| { |
| const GLenum src_target = s_valid_targets[src]; |
| const GLenum dst_target = s_valid_targets[dst]; |
| testCase test_case = { src_target, dst_target, GL_NO_ERROR }; |
| |
| if (Utils::isTargetMultisampled(dst_target) != Utils::isTargetMultisampled(src_target)) |
| { |
| test_case.m_expected_result = GL_INVALID_OPERATION; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /* Invalid source, invalid dst */ |
| for (GLuint src = 0; src < s_n_invalid_targets; ++src) |
| { |
| for (GLuint dst = 0; dst < s_n_invalid_targets; ++dst) |
| { |
| const GLenum src_target = s_invalid_targets[src]; |
| const GLenum dst_target = s_invalid_targets[dst]; |
| const testCase test_case = { src_target, dst_target, GL_INVALID_ENUM }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /* Invalid source, valid dst */ |
| for (GLuint src = 0; src < s_n_invalid_targets; ++src) |
| { |
| for (GLuint dst = 0; dst < s_n_valid_targets; ++dst) |
| { |
| const GLenum src_target = s_invalid_targets[src]; |
| const GLenum dst_target = s_valid_targets[dst]; |
| const testCase test_case = { src_target, dst_target, GL_INVALID_ENUM }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /* Valid source, invalid dst */ |
| for (GLuint src = 0; src < s_n_valid_targets; ++src) |
| { |
| for (GLuint dst = 0; dst < s_n_invalid_targets; ++dst) |
| { |
| const GLenum src_target = s_valid_targets[src]; |
| const GLenum dst_target = s_invalid_targets[dst]; |
| const testCase test_case = { src_target, dst_target, GL_INVALID_ENUM }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult InvalidTargetTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_dst_target, GL_RGBA8, GL_RGBA, |
| GL_UNSIGNED_BYTE, m_dst_buf_name); |
| m_src_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_src_target, GL_RGBA8, GL_RGBA, |
| GL_UNSIGNED_BYTE, m_src_buf_name); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_dst_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, test_case.m_src_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_src_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_dst_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Free resources */ |
| clean(); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Source target: " << glu::getTextureTargetStr(test_case.m_src_target) |
| << ", destination target: " << glu::getTextureTargetStr(test_case.m_dst_target) << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void InvalidTargetTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| /* Clean textures and buffers. Errors ignored */ |
| Utils::deleteTexture(m_context, test_case.m_dst_target, m_dst_tex_name); |
| Utils::deleteTexture(m_context, test_case.m_src_target, m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| |
| if (0 != m_dst_buf_name) |
| { |
| gl.deleteBuffers(1, &m_dst_buf_name); |
| m_dst_buf_name = 0; |
| } |
| |
| if (0 != m_src_buf_name) |
| { |
| gl.deleteBuffers(1, &m_src_buf_name); |
| m_src_buf_name = 0; |
| } |
| } |
| |
| /* TargetMismatchTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| TargetMismatchTest::TargetMismatchTest(deqp::Context& context) |
| : TestCase( |
| context, "target_miss_match", |
| "Test verifies if INVALID_ENUM is generated when target provided to CopyImageSubData does not match texture") |
| , m_dst_buf_name(0) |
| , m_dst_tex_name(0) |
| , m_src_buf_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| /* Wrong dst target */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| for (GLuint dst = 0; dst < s_n_valid_targets; ++dst) |
| { |
| const GLenum dst_target = s_valid_targets[dst]; |
| const GLenum src_target = s_valid_targets[target]; |
| const GLenum tex_target = s_valid_targets[target]; |
| testCase test_case = { tex_target, src_target, dst_target, GL_INVALID_ENUM }; |
| |
| /* Skip renderbuffers */ |
| if ((GL_RENDERBUFFER == tex_target) || (GL_RENDERBUFFER == dst_target) || (GL_RENDERBUFFER == src_target)) |
| { |
| continue; |
| } |
| |
| /* Valid case */ |
| if (dst_target == tex_target) |
| { |
| test_case.m_expected_result = GL_NO_ERROR; |
| } |
| |
| /* Skip cases with multisampling conflict */ |
| if (Utils::isTargetMultisampled(dst_target) != Utils::isTargetMultisampled(src_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /* Wrong src target */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| for (GLuint src = 0; src < s_n_valid_targets; ++src) |
| { |
| const GLenum dst_target = s_valid_targets[target]; |
| const GLenum src_target = s_valid_targets[src]; |
| const GLenum tex_target = s_valid_targets[target]; |
| testCase test_case = { tex_target, src_target, dst_target, GL_INVALID_ENUM }; |
| |
| /* Skip renderbuffers */ |
| if ((GL_RENDERBUFFER == tex_target) || (GL_RENDERBUFFER == dst_target) || (GL_RENDERBUFFER == src_target)) |
| { |
| continue; |
| } |
| |
| /* Valid case */ |
| if (src_target == tex_target) |
| { |
| test_case.m_expected_result = GL_NO_ERROR; |
| } |
| |
| /* Skip cases with multisampling conflict */ |
| if (Utils::isTargetMultisampled(dst_target) != Utils::isTargetMultisampled(src_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult TargetMismatchTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, |
| GL_UNSIGNED_BYTE, m_dst_buf_name); |
| m_src_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, |
| GL_UNSIGNED_BYTE, m_src_buf_name); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_src_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_dst_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Remove resources */ |
| clean(); |
| |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Texture target: " << glu::getTextureTargetStr(test_case.m_tex_target) |
| << ". Source target: " << glu::getTextureTargetStr(test_case.m_src_target) |
| << ", destination target: " << glu::getTextureTargetStr(test_case.m_dst_target) << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void TargetMismatchTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| |
| if (0 != m_dst_buf_name) |
| { |
| gl.deleteBuffers(1, &m_dst_buf_name); |
| m_dst_buf_name = 0; |
| } |
| |
| if (0 != m_src_buf_name) |
| { |
| gl.deleteBuffers(1, &m_src_buf_name); |
| m_src_buf_name = 0; |
| } |
| } |
| |
| /* TargetMismatchTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| IncompleteTexTest::IncompleteTexTest(deqp::Context& context) |
| : TestCase( |
| context, "incomplete_tex", |
| "Test verifies if INVALID_OPERATION is generated when texture provided to CopyImageSubData is incomplete") |
| , m_dst_buf_name(0) |
| , m_dst_tex_name(0) |
| , m_src_buf_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| testCase test_case = { tex_target, false, false, GL_INVALID_OPERATION }; |
| |
| /* Skip targets that are not multi level */ |
| if (false == Utils::isTargetMultilevel(tex_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| |
| test_case.m_is_dst_complete = true; |
| test_case.m_is_src_complete = false; |
| m_test_cases.push_back(test_case); |
| |
| test_case.m_is_dst_complete = false; |
| test_case.m_is_src_complete = true; |
| m_test_cases.push_back(test_case); |
| |
| test_case.m_is_dst_complete = true; |
| test_case.m_is_src_complete = true; |
| test_case.m_expected_result = GL_NO_ERROR; |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult IncompleteTexTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, |
| GL_UNSIGNED_BYTE, m_dst_buf_name); |
| m_src_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, |
| GL_UNSIGNED_BYTE, m_src_buf_name); |
| |
| /* Make textures complete */ |
| if (true == test_case.m_is_dst_complete) |
| { |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| } |
| |
| if (true == test_case.m_is_src_complete) |
| { |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_tex_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_tex_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Remove resources */ |
| clean(); |
| |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Texture target: " << glu::getTextureTargetStr(test_case.m_tex_target) |
| << ". Is source complete: " << test_case.m_is_src_complete |
| << ", is destination complete: " << test_case.m_is_dst_complete << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void IncompleteTexTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| |
| if (0 != m_dst_buf_name) |
| { |
| gl.deleteBuffers(1, &m_dst_buf_name); |
| m_dst_buf_name = 0; |
| } |
| |
| if (0 != m_src_buf_name) |
| { |
| gl.deleteBuffers(1, &m_src_buf_name); |
| m_src_buf_name = 0; |
| } |
| } |
| |
| /* IncompatibleFormatsTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| IncompatibleFormatsTest::IncompatibleFormatsTest(deqp::Context& context) |
| : TestCase( |
| context, "incompatible_formats", |
| "Test verifies if INVALID_OPERATION is generated when textures provided to CopyImageSubData are incompatible") |
| , m_dst_buf_name(0) |
| , m_dst_tex_name(0) |
| , m_src_buf_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| /* RGBA8UI vs RGBA16UI */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| |
| testCase test_case = { tex_target, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, |
| GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_INVALID_OPERATION }; |
| |
| /* Skip multisampled and rectangle targets */ |
| if (true == Utils::isTargetMultisampled(tex_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* RGBA8UI vs RGBA32UI */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| |
| testCase test_case = { tex_target, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, |
| GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_INVALID_OPERATION }; |
| |
| /* Skip multisampled and rectangle targets */ |
| if (true == Utils::isTargetMultisampled(tex_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* RGBA16UI vs RG16UI */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| |
| testCase test_case = { tex_target, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, |
| GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_INVALID_OPERATION }; |
| |
| /* Skip multisampled and rectangle targets */ |
| if (true == Utils::isTargetMultisampled(tex_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* RGBA32UI vs RGBA32F */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| |
| testCase test_case = { tex_target, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, |
| GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NO_ERROR }; |
| |
| /* Skip multisampled and rectangle targets */ |
| if (true == Utils::isTargetMultisampled(tex_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* RGBA8 vs RGBA32F */ |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| |
| testCase test_case = { tex_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, |
| GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_INVALID_OPERATION }; |
| |
| /* Skip multisampled and rectangle targets */ |
| if (true == Utils::isTargetMultisampled(tex_target)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult IncompatibleFormatsTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, test_case.m_dst_internal_format, |
| test_case.m_dst_format, test_case.m_dst_type, m_dst_buf_name); |
| m_src_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, test_case.m_src_internal_format, |
| test_case.m_src_format, test_case.m_src_type, m_src_buf_name); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_tex_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_tex_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Remove resources */ |
| clean(); |
| |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Texture target: " << glu::getTextureTargetStr(test_case.m_tex_target) |
| << ". Source format: " << glu::getInternalFormatParameterStr(test_case.m_src_internal_format) |
| << ". Destination format: " << glu::getInternalFormatParameterStr(test_case.m_dst_internal_format) |
| << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void IncompatibleFormatsTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| /* Clean textures and buffers. Errors ignored */ |
| Utils::deleteTexture(m_context, test_case.m_tex_target, m_dst_tex_name); |
| Utils::deleteTexture(m_context, test_case.m_tex_target, m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| |
| if (0 != m_dst_buf_name) |
| { |
| gl.deleteBuffers(1, &m_dst_buf_name); |
| m_dst_buf_name = 0; |
| } |
| |
| if (0 != m_src_buf_name) |
| { |
| gl.deleteBuffers(1, &m_src_buf_name); |
| m_src_buf_name = 0; |
| } |
| } |
| |
| /* InvalidTargetTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| SamplesMismatchTest::SamplesMismatchTest(deqp::Context& context) |
| : TestCase(context, "samples_mismatch", "Test verifies if INVALID_OPERATION is generated when textures provided " |
| "to CopyImageSubData have different number of samples") |
| , m_dst_tex_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| testCase test_case; |
| |
| static const GLsizei n_samples[2] = { 1, 4 }; |
| |
| static const GLenum targets[2] = { GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_2D_MULTISAMPLE_ARRAY }; |
| |
| for (GLuint src_sample = 0; src_sample < 2; ++src_sample) |
| { |
| for (GLuint dst_sample = 0; dst_sample < 2; ++dst_sample) |
| { |
| for (GLuint src_target = 0; src_target < 2; ++src_target) |
| { |
| for (GLuint dst_target = 0; dst_target < 2; ++dst_target) |
| { |
| test_case.m_src_target = targets[src_target]; |
| test_case.m_src_n_samples = n_samples[src_sample]; |
| test_case.m_dst_target = targets[dst_target]; |
| test_case.m_dst_n_samples = n_samples[dst_sample]; |
| |
| if (test_case.m_src_n_samples == test_case.m_dst_n_samples) |
| { |
| test_case.m_expected_result = GL_NO_ERROR; |
| } |
| else |
| { |
| test_case.m_expected_result = GL_INVALID_OPERATION; |
| } |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult SamplesMismatchTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = Utils::prepareMultisampleTex(m_context, test_case.m_dst_target, test_case.m_dst_n_samples); |
| m_src_tex_name = Utils::prepareMultisampleTex(m_context, test_case.m_src_target, test_case.m_src_n_samples); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| GLenum expected_result = test_case.m_expected_result; |
| |
| if (test_case.m_dst_n_samples > 0 && test_case.m_src_n_samples > 0) |
| { |
| /* Implementations are allowed to use more samples than requested, so we need |
| * to verify the actual sample counts allocated by the hardware and adjust |
| * the expected result if they are different from what we requested. |
| */ |
| GLint num_src_samples; |
| GLint num_dst_samples; |
| gl.bindTexture(test_case.m_dst_target, m_dst_tex_name); |
| gl.getTexLevelParameteriv(test_case.m_dst_target, 0, GL_TEXTURE_SAMPLES, &num_dst_samples); |
| gl.bindTexture(test_case.m_src_target, m_src_tex_name); |
| gl.getTexLevelParameteriv(test_case.m_src_target, 0, GL_TEXTURE_SAMPLES, &num_src_samples); |
| if (num_dst_samples != test_case.m_dst_n_samples || num_src_samples != test_case.m_src_n_samples) |
| { |
| /* The hardware allocated a different number of samples, check if this affects the expected |
| * result of the test. This can happen if we requested different sample counts but the |
| * hardware ended up allocating the same or viceversa. |
| */ |
| if (test_case.m_dst_n_samples != test_case.m_src_n_samples && num_dst_samples == num_src_samples) |
| { |
| expected_result = GL_NO_ERROR; |
| } |
| else if (test_case.m_dst_n_samples == test_case.m_src_n_samples && num_dst_samples != num_src_samples) |
| { |
| expected_result = GL_INVALID_OPERATION; |
| } |
| } |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_src_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_dst_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (expected_result == error); |
| |
| /* Free resources */ |
| clean(); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Source target: " << glu::getTextureTargetStr(test_case.m_src_target) |
| << " samples: " << test_case.m_src_n_samples |
| << ", destination target: " << glu::getTextureTargetStr(test_case.m_dst_target) |
| << " samples: " << test_case.m_dst_n_samples << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void SamplesMismatchTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures . Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| } |
| |
| /* IncompatibleFormatsCompressionTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| IncompatibleFormatsCompressionTest::IncompatibleFormatsCompressionTest(deqp::Context& context) |
| : TestCase(context, "incompatible_formats_compression", "Test verifies if INVALID_OPERATION is generated when " |
| "textures provided to CopyImageSubData are incompatible, " |
| "one of formats is compressed") |
| , m_dst_tex_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| |
| /* Skip 1D targets, not supported */ |
| if ((GL_TEXTURE_1D == tex_target) || (GL_TEXTURE_1D_ARRAY == tex_target) || (GL_TEXTURE_3D == tex_target) || |
| (GL_TEXTURE_RECTANGLE == tex_target) || (GL_RENDERBUFFER == tex_target) || (GL_TEXTURE_CUBE_MAP_ARRAY == tex_target)) |
| { |
| continue; |
| } |
| |
| /* Skip multisampled and rectangle targets */ |
| if (true == Utils::isTargetMultisampled(tex_target)) |
| { |
| continue; |
| } |
| |
| /* Compressed 128bit vs RGBA32UI */ |
| { |
| testCase test_case = { |
| tex_target, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_COMPRESSED_RG_RGTC2, |
| GL_RG, GL_UNSIGNED_BYTE, GL_NO_ERROR |
| }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* Compressed 128bit vs RGBA16UI */ |
| { |
| testCase test_case = { |
| tex_target, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_COMPRESSED_RG_RGTC2, |
| GL_RG, GL_UNSIGNED_BYTE, GL_INVALID_OPERATION |
| }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult IncompatibleFormatsCompressionTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLuint temp = 0; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, test_case.m_dst_internal_format, |
| test_case.m_dst_format, test_case.m_dst_type, temp); |
| m_src_tex_name = Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, test_case.m_src_internal_format, |
| test_case.m_src_format, test_case.m_src_type, temp); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_tex_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_tex_target, 0 /* dstLevel */, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 4 /* srcWidth */, 4 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Remove resources */ |
| clean(); |
| |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Texture target: " << glu::getTextureTargetStr(test_case.m_tex_target) |
| << ". Source format: " << glu::getInternalFormatParameterStr(test_case.m_src_internal_format) |
| << ". Destination format: " << glu::getInternalFormatParameterStr(test_case.m_dst_internal_format) |
| << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void IncompatibleFormatsCompressionTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| } |
| |
| /* InvalidObjectTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| InvalidObjectTest::InvalidObjectTest(deqp::Context& context) |
| : TestCase( |
| context, "invalid_object", |
| "Test verifies if INVALID_VALUE is generated when object & target provided to CopyImageSubData do not match") |
| , m_dst_name(0) |
| , m_src_name(0) |
| , m_test_case_index(0) |
| { |
| static glw::GLenum arg_types[] = { GL_TEXTURE_2D, GL_RENDERBUFFER }; |
| static const GLuint n_arg_types = sizeof(arg_types) / sizeof(arg_types[0]); |
| |
| for (GLuint dst = 0; dst < n_arg_types; dst++) |
| { |
| for (GLuint src = 0; src < n_arg_types; src++) |
| { |
| for (GLuint dst_valid = 0; dst_valid < 2; dst_valid++) |
| { |
| for (GLuint src_valid = 0; src_valid < 2; src_valid++) |
| { |
| glw::GLenum expected_error = GL_INVALID_VALUE; |
| if (!!src_valid && !!dst_valid) |
| { |
| expected_error = GL_NO_ERROR; |
| } |
| const testCase test_case = { arg_types[dst], !!dst_valid, arg_types[src], !!src_valid, |
| expected_error }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult InvalidObjectTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLuint temp = 0; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare objects */ |
| if (GL_RENDERBUFFER == test_case.m_dst_target) |
| { |
| m_dst_name = Utils::prepareRenderBuffer(m_context, GL_RGBA8); |
| } |
| else |
| { |
| m_dst_name = |
| Utils::prepareTex16x16x6(m_context, test_case.m_dst_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, temp); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_dst_target, m_dst_name, 0 /* base */, 0 /* max */); |
| } |
| |
| if (GL_RENDERBUFFER == test_case.m_src_target) |
| { |
| m_src_name = Utils::prepareRenderBuffer(m_context, GL_RGBA8); |
| } |
| else |
| { |
| m_src_name = |
| Utils::prepareTex16x16x6(m_context, test_case.m_src_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, temp); |
| |
| /* Make texture complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_src_target, m_src_name, 0 /* base */, 0 /* max */); |
| } |
| |
| /* If an object is invalid, free it before use to make it invalid */ |
| if (!test_case.m_dst_valid) |
| { |
| Utils::deleteTexture(m_context, test_case.m_dst_target, m_dst_name); |
| } |
| |
| if (!test_case.m_src_valid) |
| { |
| Utils::deleteTexture(m_context, test_case.m_src_target, m_src_name); |
| } |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_name, test_case.m_src_target, 0 /* srcLevel */, 0 /* srcX */, 0 /* srcY */, 0 /* srcZ */, |
| m_dst_name, test_case.m_dst_target, 0 /* dstLevel */, 0 /* dstX */, 0 /* dstY */, 0 /* dstZ */, |
| 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Remove resources */ |
| clean(); |
| |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Destination target: " << glu::getTextureTargetStr(test_case.m_dst_target) |
| << ". Destination valid: " << (test_case.m_src_valid ? "true" : "false") |
| << ". Source target: " << glu::getTextureTargetStr(test_case.m_dst_target) |
| << ". Source valid: " << (test_case.m_dst_valid ? "true" : "false") << "." << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void InvalidObjectTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| /* Clean textures or renderbuffers. Errors ignored */ |
| if (test_case.m_dst_valid) |
| { |
| if (GL_RENDERBUFFER == test_case.m_dst_target) |
| { |
| gl.deleteRenderbuffers(1, &m_dst_name); |
| } |
| else |
| { |
| gl.deleteTextures(1, &m_dst_name); |
| } |
| } |
| if (test_case.m_src_valid) |
| { |
| if (GL_RENDERBUFFER == test_case.m_src_target) |
| { |
| gl.deleteRenderbuffers(1, &m_src_name); |
| } |
| else |
| { |
| gl.deleteTextures(1, &m_src_name); |
| } |
| } |
| |
| m_dst_name = 0; |
| m_src_name = 0; |
| } |
| |
| /* NonExistentMipMapTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| NonExistentMipMapTest::NonExistentMipMapTest(deqp::Context& context) |
| : TestCase(context, "non_existent_mipmap", "Test verifies if INVALID_VALUE is generated when CopyImageSubData is " |
| "executed for mipmap that does not exist") |
| , m_dst_tex_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| testCase test_case = { tex_target, 0, 0, GL_NO_ERROR }; |
| |
| if (GL_RENDERBUFFER == tex_target) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back(test_case); |
| |
| /* Rest of cases is invalid */ |
| test_case.m_expected_result = GL_INVALID_VALUE; |
| |
| test_case.m_dst_level = 1; |
| test_case.m_src_level = 0; |
| m_test_cases.push_back(test_case); |
| |
| test_case.m_dst_level = 0; |
| test_case.m_src_level = 1; |
| m_test_cases.push_back(test_case); |
| |
| test_case.m_dst_level = 1; |
| test_case.m_src_level = 1; |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult NonExistentMipMapTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLuint temp = 0; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = |
| Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, temp); |
| m_src_tex_name = |
| Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, temp); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_tex_target, test_case.m_src_level, 0 /* srcX */, 0 /* srcY */, |
| 0 /* srcZ */, m_dst_tex_name, test_case.m_tex_target, test_case.m_dst_level, 0 /* dstX */, |
| 0 /* dstY */, 0 /* dstZ */, 1 /* srcWidth */, 1 /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Free resources */ |
| clean(); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Texture target: " << glu::getTextureTargetStr(test_case.m_tex_target) |
| << ", source level: " << test_case.m_src_level << ", destination level: " << test_case.m_dst_level |
| << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void NonExistentMipMapTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| } |
| |
| /* ExceedingBoundariesTest */ |
| const glw::GLuint ExceedingBoundariesTest::m_region_depth = 4; |
| const glw::GLuint ExceedingBoundariesTest::m_region_height = 4; |
| const glw::GLuint ExceedingBoundariesTest::m_region_width = 4; |
| |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| ExceedingBoundariesTest::ExceedingBoundariesTest(deqp::Context& context) |
| : TestCase(context, "exceeding_boundaries", "Test verifies if INVALID_VALUE is generated when CopyImageSubData is " |
| "executed for regions exceeding image boundaries") |
| , m_dst_tex_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| /* 16x16x6 are values used by prepareTex16x16x6 */ |
| static const GLuint invalid_x = 16 - (m_region_width / 2); |
| static const GLuint invalid_y = 16 - (m_region_height / 2); |
| static const GLuint invalid_z = 6 - (m_region_depth / 2); |
| |
| static const GLuint x_vals[] = { 0, invalid_x }; |
| static const GLuint y_vals[] = { 0, invalid_y }; |
| static const GLuint z_vals[] = { 0, invalid_z }; |
| |
| static const GLuint n_x_vals = sizeof(x_vals) / sizeof(x_vals[0]); |
| static const GLuint n_y_vals = sizeof(y_vals) / sizeof(y_vals[0]); |
| static const GLuint n_z_vals = sizeof(z_vals) / sizeof(z_vals[0]); |
| |
| for (GLuint target = 0; target < s_n_valid_targets; ++target) |
| { |
| const GLenum tex_target = s_valid_targets[target]; |
| GLuint height = m_region_height; |
| |
| if (GL_TEXTURE_BUFFER == tex_target) |
| { |
| continue; |
| } |
| |
| if ((GL_TEXTURE_1D == tex_target) || (GL_TEXTURE_1D_ARRAY == tex_target)) |
| { |
| height = 1; |
| } |
| |
| for (GLuint x = 0; x < n_x_vals; ++x) |
| { |
| for (GLuint y = 0; y < n_y_vals; ++y) |
| { |
| for (GLuint z = 0; z < n_z_vals; ++z) |
| { |
| const GLuint x_val = x_vals[x]; |
| const GLuint y_val = y_vals[y]; |
| const GLuint z_val = z_vals[z]; |
| const GLenum res = ((0 == x_val) && (0 == y_val) && (0 == z_val)) ? GL_NO_ERROR : GL_INVALID_VALUE; |
| GLuint depth = 1; |
| |
| if (0 != z_val) |
| { |
| if ((GL_TEXTURE_2D_ARRAY != tex_target) || (GL_TEXTURE_2D_MULTISAMPLE_ARRAY != tex_target) || |
| (GL_TEXTURE_3D != tex_target) || (GL_TEXTURE_CUBE_MAP_ARRAY != tex_target)) |
| { |
| /* Skip z != 0 for 2d textures */ |
| continue; |
| } |
| else |
| { |
| /* Set depth so as to exceed boundary */ |
| depth = m_region_depth; |
| } |
| } |
| |
| testCase src_test_case = { tex_target, depth, height, x_val, y_val, z_val, 0, 0, 0, res }; |
| |
| testCase dst_test_case = { tex_target, depth, height, 0, 0, 0, x_val, y_val, z_val, res }; |
| |
| m_test_cases.push_back(src_test_case); |
| m_test_cases.push_back(dst_test_case); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult ExceedingBoundariesTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLuint temp = 0; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = |
| Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, temp); |
| m_src_tex_name = |
| Utils::prepareTex16x16x6(m_context, test_case.m_tex_target, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, temp); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, test_case.m_tex_target, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, test_case.m_tex_target, 0 /* level */, test_case.m_src_x /* srcX */, |
| test_case.m_src_y /* srcY */, test_case.m_src_z /* srcZ */, m_dst_tex_name, |
| test_case.m_tex_target, 0 /* level */, test_case.m_dst_x /* dstX */, |
| test_case.m_dst_y /* dstY */, test_case.m_dst_z /* dstZ */, m_region_width /* srcWidth */, |
| test_case.m_height /* srcHeight */, test_case.m_depth /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Free resources */ |
| clean(); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) |
| << ". Texture target: " << glu::getTextureTargetStr(test_case.m_tex_target) << ", source: [" |
| << test_case.m_src_x << ", " << test_case.m_src_y << ", " << test_case.m_src_z << "], destination: [" |
| << test_case.m_src_x << ", " << test_case.m_src_y << ", " << test_case.m_src_z |
| << "], depth: " << test_case.m_depth << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void ExceedingBoundariesTest::clean() |
| { |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| /* Clean textures and buffers. Errors ignored */ |
| Utils::deleteTexture(m_context, test_case.m_tex_target, m_dst_tex_name); |
| Utils::deleteTexture(m_context, test_case.m_tex_target, m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| } |
| |
| /* InvalidAlignmentTest */ |
| /** Constructor |
| * |
| * @param context Text context |
| **/ |
| InvalidAlignmentTest::InvalidAlignmentTest(deqp::Context& context) |
| : TestCase(context, "invalid_alignment", "Test verifies if INVALID_VALUE is generated when CopyImageSubData is " |
| "executed for regions with invalid alignment") |
| , m_dst_tex_name(0) |
| , m_src_tex_name(0) |
| , m_test_case_index(0) |
| { |
| /* 16x16x6 are values used by prepareTex16x16x6 */ |
| static const GLuint invalid_h = 2; |
| static const GLuint invalid_w = 2; |
| static const GLuint invalid_x = 2; |
| static const GLuint invalid_y = 2; |
| static const GLuint valid_h = 4; |
| static const GLuint valid_w = 4; |
| |
| static const GLuint h_vals[] = { valid_h, invalid_h }; |
| static const GLuint w_vals[] = { valid_w, invalid_w }; |
| static const GLuint x_vals[] = { 0, invalid_x }; |
| static const GLuint y_vals[] = { 0, invalid_y }; |
| |
| static const GLuint n_h_vals = sizeof(h_vals) / sizeof(h_vals[0]); |
| static const GLuint n_w_vals = sizeof(w_vals) / sizeof(w_vals[0]); |
| static const GLuint n_x_vals = sizeof(x_vals) / sizeof(x_vals[0]); |
| static const GLuint n_y_vals = sizeof(y_vals) / sizeof(y_vals[0]); |
| |
| for (GLuint x = 0; x < n_x_vals; ++x) |
| { |
| for (GLuint y = 0; y < n_y_vals; ++y) |
| { |
| for (GLuint h = 0; h < n_h_vals; ++h) |
| { |
| for (GLuint w = 0; w < n_w_vals; ++w) |
| { |
| const GLuint h_val = h_vals[h]; |
| const GLuint w_val = w_vals[w]; |
| const GLuint x_val = x_vals[x]; |
| const GLuint y_val = y_vals[y]; |
| const GLenum res = ((valid_h == h_val) && (valid_w == w_val) && (0 == x_val) && (0 == y_val)) ? |
| GL_NO_ERROR : |
| GL_INVALID_VALUE; |
| |
| testCase dst_test_case = { h_val, w_val, 0, 0, x_val, y_val, res }; |
| |
| testCase src_test_case = { h_val, w_val, x_val, y_val, 0, 0, res }; |
| |
| m_test_cases.push_back(dst_test_case); |
| m_test_cases.push_back(src_test_case); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return CONTINUE as long there are more test case, STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult InvalidAlignmentTest::iterate() |
| { |
| GLenum error = GL_NO_ERROR; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| tcu::TestNode::IterateResult it_result = tcu::TestNode::STOP; |
| bool result = false; |
| GLuint temp = 0; |
| const testCase& test_case = m_test_cases[m_test_case_index]; |
| |
| try |
| { |
| /* Prepare textures */ |
| m_dst_tex_name = |
| Utils::prepareTex16x16x6(m_context, GL_TEXTURE_2D, GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, temp); |
| m_src_tex_name = |
| Utils::prepareTex16x16x6(m_context, GL_TEXTURE_2D, GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, temp); |
| |
| /* Make textures complete */ |
| Utils::makeTextureComplete(m_context, GL_TEXTURE_2D, m_dst_tex_name, 0 /* base */, 0 /* max */); |
| Utils::makeTextureComplete(m_context, GL_TEXTURE_2D, m_src_tex_name, 0 /* base */, 0 /* max */); |
| } |
| catch (tcu::Exception& exc) |
| { |
| clean(); |
| throw exc; |
| } |
| |
| /* Execute CopyImageSubData */ |
| gl.copyImageSubData(m_src_tex_name, GL_TEXTURE_2D, 0 /* level */, test_case.m_src_x /* srcX */, |
| test_case.m_src_y /* srcY */, 0 /* srcZ */, m_dst_tex_name, GL_TEXTURE_2D, 0 /* level */, |
| test_case.m_dst_x /* dstX */, test_case.m_dst_y /* dstY */, 0 /* dstZ */, |
| test_case.m_width /* srcWidth */, test_case.m_height /* srcHeight */, 1 /* srcDepth */); |
| |
| /* Verify generated error */ |
| error = gl.getError(); |
| result = (test_case.m_expected_result == error); |
| |
| /* Free resources */ |
| clean(); |
| |
| /* Set result */ |
| if (true == result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| |
| /* Increase index */ |
| m_test_case_index += 1; |
| |
| /* Are there any test cases left */ |
| if (m_test_cases.size() > m_test_case_index) |
| { |
| it_result = tcu::TestNode::CONTINUE; |
| } |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Expected result: " << glu::getErrorStr(test_case.m_expected_result) |
| << " got: " << glu::getErrorStr(error) << ". source: [" << test_case.m_src_x << ", " << test_case.m_src_y |
| << "], destination: [" << test_case.m_src_x << ", " << test_case.m_src_y << "], size: " << test_case.m_width |
| << " x " << test_case.m_height << tcu::TestLog::EndMessage; |
| |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return it_result; |
| } |
| |
| /** Cleans resources |
| * |
| **/ |
| void InvalidAlignmentTest::clean() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean textures and buffers. Errors ignored */ |
| gl.deleteTextures(1, &m_dst_tex_name); |
| gl.deleteTextures(1, &m_src_tex_name); |
| |
| m_dst_tex_name = 0; |
| m_src_tex_name = 0; |
| } |
| } /* namespace CopyImage */ |
| |
| CopyImageTests::CopyImageTests(deqp::Context& context) : TestCaseGroup(context, "copy_image", "") |
| { |
| } |
| |
| CopyImageTests::~CopyImageTests(void) |
| { |
| } |
| |
| void CopyImageTests::init() |
| { |
| addChild(new CopyImage::FunctionalTest(m_context)); |
| addChild(new CopyImage::IncompleteTexTest(m_context)); |
| addChild(new CopyImage::InvalidObjectTest(m_context)); |
| addChild(new CopyImage::SmokeTest(m_context)); |
| addChild(new CopyImage::InvalidTargetTest(m_context)); |
| addChild(new CopyImage::TargetMismatchTest(m_context)); |
| addChild(new CopyImage::IncompatibleFormatsTest(m_context)); |
| addChild(new CopyImage::SamplesMismatchTest(m_context)); |
| addChild(new CopyImage::IncompatibleFormatsCompressionTest(m_context)); |
| addChild(new CopyImage::NonExistentMipMapTest(m_context)); |
| addChild(new CopyImage::ExceedingBoundariesTest(m_context)); |
| addChild(new CopyImage::InvalidAlignmentTest(m_context)); |
| } |
| } /* namespace gl4cts */ |