| /*------------------------------------------------------------------------- |
| * 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 gl4cCopyImageTests.cpp |
| * \brief Implements CopyImageSubData functional tests. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #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"); |
| } |
| |
| 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"); |
| } |
| |
| 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"); |
| } |
| |
| 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"); |
| } |
| |
| 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"); |
| } |
| |
| 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"); |
| } |
| |
| /* 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"); |
| } |
| |
| 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"); |
| } |
| } |
| |
| /** 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"); |
| } |
| } |
| |
| /** 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"); |
| } |
| } |
| |
| /** 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"); |
| } |
| } |
| |
| /** 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"); |
| } |
| } |
| |
| /** 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"); |
| } |
| } |
| |
| 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)<
|