Add tests for GL_EXT_copy_image.
authorMika Isojärvi <misojarvi@google.com>
Fri, 16 Jan 2015 19:18:36 +0000 (11:18 -0800)
committerMika Isojärvi <misojarvi@google.com>
Wed, 11 Feb 2015 23:56:22 +0000 (15:56 -0800)
New tests that test GL_EXT_copy_image extension. Tests copy between all
possible format combinations except two float formats. For each format
combination all image target combinations are tested. These tests
always use npot image sizes and npot copy sizes. Offset to source and
destination image is also always npot. When testing texture images,
mipmap complete textures are used and source and destination mipmap
level is always 1. Each test case first tests copying between images
after rendering them to screen and then tests copying between images
immediately after creating them.

Change-Id: If961728d0257109a8cbd97ef8380dd9d89320ecd

Android.mk
doc/testspecs/GLES31/functional.copy_image.txt [new file with mode: 0644]
modules/gles31/functional/CMakeLists.txt
modules/gles31/functional/es31fCopyImageTests.cpp [new file with mode: 0644]
modules/gles31/functional/es31fCopyImageTests.hpp [new file with mode: 0644]
modules/gles31/functional/es31fFunctionalTests.cpp

index 1ef241e..5b9865c 100644 (file)
@@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \
        modules/gles31/functional/es31fUniformLocationTests.cpp \
        modules/gles31/functional/es31fVertexAttributeBindingStateQueryTests.cpp \
        modules/gles31/functional/es31fVertexAttributeBindingTests.cpp \
+       modules/gles31/functional/es31fCopyImageTests.cpp \
        modules/gles31/stress/es31sDrawTests.cpp \
        modules/gles31/stress/es31sStressTests.cpp \
        modules/gles31/stress/es31sTessellationGeometryInteractionTests.cpp \
diff --git a/doc/testspecs/GLES31/functional.copy_image.txt b/doc/testspecs/GLES31/functional.copy_image.txt
new file mode 100644 (file)
index 0000000..8e6d324
--- /dev/null
@@ -0,0 +1,67 @@
+-------------------------------------------------------------------------
+drawElements Quality Program Test Specification
+-----------------------------------------------
+
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-------------------------------------------------------------------------
+    Copy Image Tests (GL_EXT_copy_image)
+
+Tests:
+ + dEQP-GLES31.copy_image.*
+
+Includes:
+ + 2D texture images
+ + Cube map texture images
+ + 3D texture images
+ + 2D texture array images
+ + Renderbuffer images
+ + Copies between different formats
+ + Copies between different compressed formats
+ + Copies between compressed and non-compressed formats
+ + Using images for rendering before copy
+ + Not using images for rendering before copy
+ + Compressed ASTC formats
+ + Compressed ETC formats
+ + Compressed ETC2 formats
+
+Excludes:
+ + Copies between two float formats
+ + Invalid ASTC blocks
+ + HDR ASTC blocks
+ + 3D block ASTC formats
+ + Other compressed formats than ASTC, ETC and ETC2
+
+Description:
+
+Test creates two images and initializes them to random data. Both images have
+always npot size and texture images are always created so that they are mipmap
+complete. Random data is always generated so that it is valid for both formats
+e.g. no invalid ASTC blocks or NaNs exist before or after copying.
+
+Multiple copies are performed per test case. Texture levels 0, 1 and last level
+are used as source and destination levels. For each texture level top left and
+bottom right corners are used as source rectangle and destination rectangle.
+Also npot offset in the middle of the image is used. Some of the copied
+rectangles are npot size.
+
+Each test case does copying in two different ways. First they create images,
+use them for rendering, copy and perform verification. Second time they create
+images and immediately copy them without rendering and finally verify image
+contents.
+
+Instead of trying to isolate different smaller features and testing them
+separately, these tests try to test multiple cases for each format as there
+would be huge number of tests and it would take too long to run more than one
+case for each format and image combination.
index f3ca374..85aeb99 100644 (file)
@@ -137,6 +137,8 @@ set(DEQP_GLES31_FUNCTIONAL_SRCS
        es31fShaderHelperInvocationTests.hpp
        es31fPrimitiveBoundingBoxTests.cpp
        es31fPrimitiveBoundingBoxTests.hpp
+       es31fCopyImageTests.hpp
+       es31fCopyImageTests.cpp
        )
 
 add_library(deqp-gles31-functional STATIC ${DEQP_GLES31_FUNCTIONAL_SRCS})
diff --git a/modules/gles31/functional/es31fCopyImageTests.cpp b/modules/gles31/functional/es31fCopyImageTests.cpp
new file mode 100644 (file)
index 0000000..b0bf789
--- /dev/null
@@ -0,0 +1,2425 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Copy image tests for GL_EXT_copy_image.
+ *//*--------------------------------------------------------------------*/
+
+#include "es31fCopyImageTests.hpp"
+
+#include "tes31TestCase.hpp"
+
+#include "glsTextureTestUtil.hpp"
+
+#include "gluContextInfo.hpp"
+#include "gluObjectWrapper.hpp"
+#include "gluRenderContext.hpp"
+#include "gluStrUtil.hpp"
+#include "gluTextureUtil.hpp"
+#include "gluPixelTransfer.hpp"
+
+#include "glwEnums.hpp"
+#include "glwFunctions.hpp"
+
+#include "tcuCompressedTexture.hpp"
+#include "tcuFloat.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuTexture.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuVector.hpp"
+#include "tcuVectorUtil.hpp"
+#include "tcuSeedBuilder.hpp"
+
+#include "deArrayBuffer.hpp"
+#include "deFloat16.h"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <map>
+#include <string>
+#include <vector>
+
+using namespace deqp::gls::TextureTestUtil;
+
+using tcu::Float;
+using tcu::IVec3;
+using tcu::Sampler;
+using tcu::ScopedLogSection;
+using tcu::TestLog;
+using tcu::Vec4;
+using tcu::SeedBuilder;
+
+using de::ArrayBuffer;
+
+using std::map;
+using std::string;
+using std::vector;
+using std::pair;
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+namespace
+{
+
+enum ViewClass
+{
+       VIEWCLASS_128_BITS = 0,
+       VIEWCLASS_96_BITS,
+       VIEWCLASS_64_BITS,
+       VIEWCLASS_48_BITS,
+       VIEWCLASS_32_BITS,
+       VIEWCLASS_24_BITS,
+       VIEWCLASS_16_BITS,
+       VIEWCLASS_8_BITS,
+
+       VIEWCLASS_EAC_R11,
+       VIEWCLASS_EAC_RG11,
+       VIEWCLASS_ETC2_RGB,
+       VIEWCLASS_ETC2_RGBA,
+       VIEWCLASS_ETC2_EAC_RGBA,
+       VIEWCLASS_ASTC_4x4_RGBA,
+       VIEWCLASS_ASTC_5x4_RGBA,
+       VIEWCLASS_ASTC_5x5_RGBA,
+       VIEWCLASS_ASTC_6x5_RGBA,
+       VIEWCLASS_ASTC_6x6_RGBA,
+       VIEWCLASS_ASTC_8x5_RGBA,
+       VIEWCLASS_ASTC_8x6_RGBA,
+       VIEWCLASS_ASTC_8x8_RGBA,
+       VIEWCLASS_ASTC_10x5_RGBA,
+       VIEWCLASS_ASTC_10x6_RGBA,
+       VIEWCLASS_ASTC_10x8_RGBA,
+       VIEWCLASS_ASTC_10x10_RGBA,
+       VIEWCLASS_ASTC_12x10_RGBA,
+       VIEWCLASS_ASTC_12x12_RGBA
+};
+
+const char* viewClassToName (ViewClass viewClass)
+{
+       switch (viewClass)
+       {
+               case VIEWCLASS_128_BITS:                        return "viewclass_128_bits";
+               case VIEWCLASS_96_BITS:                         return "viewclass_96_bits";
+               case VIEWCLASS_64_BITS:                         return "viewclass_64_bits";
+               case VIEWCLASS_48_BITS:                         return "viewclass_48_bits";
+               case VIEWCLASS_32_BITS:                         return "viewclass_32_bits";
+               case VIEWCLASS_24_BITS:                         return "viewclass_24_bits";
+               case VIEWCLASS_16_BITS:                         return "viewclass_16_bits";
+               case VIEWCLASS_8_BITS:                          return "viewclass_8_bits";
+               case VIEWCLASS_EAC_R11:                         return "viewclass_eac_r11";
+               case VIEWCLASS_EAC_RG11:                        return "viewclass_eac_rg11";
+               case VIEWCLASS_ETC2_RGB:                        return "viewclass_etc2_rgb";
+               case VIEWCLASS_ETC2_RGBA:                       return "viewclass_etc2_rgba";
+               case VIEWCLASS_ETC2_EAC_RGBA:           return "viewclass_etc2_eac_rgba";
+               case VIEWCLASS_ASTC_4x4_RGBA:           return "viewclass_astc_4x4_rgba";
+               case VIEWCLASS_ASTC_5x4_RGBA:           return "viewclass_astc_5x4_rgba";
+               case VIEWCLASS_ASTC_5x5_RGBA:           return "viewclass_astc_5x5_rgba";
+               case VIEWCLASS_ASTC_6x5_RGBA:           return "viewclass_astc_6x5_rgba";
+               case VIEWCLASS_ASTC_6x6_RGBA:           return "viewclass_astc_6x6_rgba";
+               case VIEWCLASS_ASTC_8x5_RGBA:           return "viewclass_astc_8x5_rgba";
+               case VIEWCLASS_ASTC_8x6_RGBA:           return "viewclass_astc_8x6_rgba";
+               case VIEWCLASS_ASTC_8x8_RGBA:           return "viewclass_astc_8x8_rgba";
+               case VIEWCLASS_ASTC_10x5_RGBA:          return "viewclass_astc_10x5_rgba";
+               case VIEWCLASS_ASTC_10x6_RGBA:          return "viewclass_astc_10x6_rgba";
+               case VIEWCLASS_ASTC_10x8_RGBA:          return "viewclass_astc_10x8_rgba";
+               case VIEWCLASS_ASTC_10x10_RGBA:         return "viewclass_astc_10x10_rgba";
+               case VIEWCLASS_ASTC_12x10_RGBA:         return "viewclass_astc_12x10_rgba";
+               case VIEWCLASS_ASTC_12x12_RGBA:         return "viewclass_astc_12x12_rgba";
+
+               default:
+                       DE_ASSERT(false);
+                       return NULL;
+       }
+}
+
+const char* targetToName (deUint32 target)
+{
+       switch (target)
+       {
+               case GL_RENDERBUFFER:           return "renderbuffer";
+               case GL_TEXTURE_2D:                     return "texture2d";
+               case GL_TEXTURE_3D:                     return "texture3d";
+               case GL_TEXTURE_2D_ARRAY:       return "texture2d_array";
+               case GL_TEXTURE_CUBE_MAP:       return "cubemap";
+
+               default:
+                       DE_ASSERT(false);
+                       return NULL;
+       }
+}
+
+bool isCompressedFormat (deUint32 format)
+{
+       switch (format)
+       {
+               case GL_COMPRESSED_R11_EAC:
+               case GL_COMPRESSED_SIGNED_R11_EAC:
+               case GL_COMPRESSED_RG11_EAC:
+               case GL_COMPRESSED_SIGNED_RG11_EAC:
+               case GL_COMPRESSED_RGB8_ETC2:
+               case GL_COMPRESSED_SRGB8_ETC2:
+               case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+               case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+               case GL_COMPRESSED_RGBA8_ETC2_EAC:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+               case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
+               case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+               case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+string formatToName (deUint32 format)
+{
+       string enumName;
+
+       if (isCompressedFormat(format))
+               enumName = glu::getCompressedTexFormatStr(format).toString().substr(14); // Strip GL_COMPRESSED_
+       else
+               enumName = glu::getPixelFormatStr(format).toString().substr(3); // Strip GL_
+
+       return de::toLower(enumName);
+}
+
+bool isFloatFormat (deUint32 format)
+{
+       if (isCompressedFormat(format))
+               return false;
+       else
+               return tcu::getTextureChannelClass(glu::mapGLInternalFormat(format).type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
+}
+
+bool isUintFormat (deUint32 format)
+{
+       if (isCompressedFormat(format))
+               return false;
+       else
+               return tcu::getTextureChannelClass(glu::mapGLInternalFormat(format).type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
+}
+
+bool isIntFormat (deUint32 format)
+{
+       if (isCompressedFormat(format))
+               return false;
+       else
+               return tcu::getTextureChannelClass(glu::mapGLInternalFormat(format).type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
+}
+
+bool isTextureTarget (deUint32 target)
+{
+       return target != GL_RENDERBUFFER;
+}
+
+int getTargetTexDims (deUint32 target)
+{
+       DE_ASSERT(isTextureTarget(target));
+
+       switch (target)
+       {
+               case GL_TEXTURE_1D:
+                       return 1;
+
+               case GL_TEXTURE_1D_ARRAY:
+               case GL_TEXTURE_2D:
+               case GL_TEXTURE_CUBE_MAP:
+                       return 2;
+
+               case GL_TEXTURE_2D_ARRAY:
+               case GL_TEXTURE_3D:
+                       return 3;
+
+               default:
+                       DE_ASSERT(false);
+                       return -1;
+       }
+}
+
+class ImageInfo
+{
+public:
+                                       ImageInfo               (deUint32 format, deUint32 target, const IVec3& size);
+
+       deUint32                getFormat               (void) const { return m_format; }
+       deUint32                getTarget               (void) const { return m_target; }
+       const IVec3&    getSize                 (void) const { return m_size; }
+
+private:
+       deUint32                m_format;
+       deUint32                m_target;
+       IVec3                   m_size;
+};
+
+ImageInfo::ImageInfo (deUint32 format, deUint32 target, const IVec3& size)
+       : m_format              (format)
+       , m_target              (target)
+       , m_size                (size)
+{
+       DE_ASSERT(m_target == GL_TEXTURE_2D_ARRAY || m_target == GL_TEXTURE_3D || m_size.z() == 1);
+       DE_ASSERT(isTextureTarget(m_target) || !isCompressedFormat(m_target));
+}
+
+
+SeedBuilder& operator<< (SeedBuilder& builder, const ImageInfo& info)
+{
+       builder << info.getFormat() << info.getTarget() << info.getSize();
+       return builder;
+}
+
+const glu::ObjectTraits& getObjectTraits (const ImageInfo& info)
+{
+       if (isTextureTarget(info.getTarget()))
+               return glu::objectTraits(glu::OBJECTTYPE_TEXTURE);
+       else
+               return glu::objectTraits(glu::OBJECTTYPE_RENDERBUFFER);
+}
+
+int getLevelCount (const ImageInfo& info)
+{
+       const deUint32  target  = info.getTarget();
+       const IVec3             size    = info.getSize();
+
+       if (target == GL_RENDERBUFFER)
+               return 1;
+       else if (target == GL_TEXTURE_2D_ARRAY)
+       {
+               const int maxSize = de::max(size.x(), size.y());
+
+               return deLog2Ceil32(maxSize);
+       }
+       else
+       {
+               const int maxSize = de::max(size.x(), de::max(size.y(), size.z()));
+
+               return deLog2Ceil32(maxSize);
+       }
+}
+
+// Return format that has more restrictions on texel data.
+deUint32 getMoreRestrictiveFormat (deUint32 formatA, deUint32 formatB)
+{
+       if (formatA == formatB)
+               return formatA;
+       else if (isCompressedFormat(formatA) && isAstcFormat(glu::mapGLCompressedTexFormat(formatA)))
+               return formatA;
+       else if (isCompressedFormat(formatB) && isAstcFormat(glu::mapGLCompressedTexFormat(formatB)))
+               return formatB;
+       else if (isFloatFormat(formatA))
+       {
+               DE_ASSERT(!isFloatFormat(formatB));
+
+               return formatA;
+       }
+       else if (isFloatFormat(formatB))
+       {
+               DE_ASSERT(!isFloatFormat(formatA));
+
+               return formatB;
+       }
+       else if (isCompressedFormat(formatA))
+       {
+               return formatA;
+       }
+       else if (isCompressedFormat(formatB))
+       {
+               return formatB;
+       }
+       else
+               return formatA;
+}
+
+int getTexelBlockSize (deUint32 format)
+{
+       if (isCompressedFormat(format))
+               return tcu::getBlockSize(glu::mapGLCompressedTexFormat(format));
+       else
+               return glu::mapGLInternalFormat(format).getPixelSize();
+}
+
+IVec3 getTexelBlockPixelSize (deUint32 format)
+{
+       if (isCompressedFormat(format))
+               return tcu::getBlockPixelSize(glu::mapGLCompressedTexFormat(format));
+       else
+               return IVec3(1, 1, 1);
+}
+
+IVec3 getLevelSize (deUint32 target, const IVec3& baseSize, int level)
+{
+       IVec3 size;
+
+       if (target != GL_TEXTURE_2D_ARRAY)
+       {
+               for (int i = 0; i < 3; i++)
+                       size[i] = de::max(baseSize[i] >> level, 1);
+       }
+       else
+       {
+               for (int i = 0; i < 2; i++)
+                       size[i] = de::max(baseSize[i] >> level, 1);
+
+               size[2] = baseSize[2];
+       }
+
+       return size;
+}
+
+bool isColorRenderable (deUint32 format)
+{
+       switch (format)
+       {
+               case GL_R8:
+               case GL_RG8:
+               case GL_RGB8:
+               case GL_RGB565:
+               case GL_RGB4:
+               case GL_RGB5_A1:
+               case GL_RGBA8:
+               case GL_RGB10_A2:
+               case GL_RGB10_A2UI:
+               case GL_SRGB8_ALPHA8:
+               case GL_R8I:
+               case GL_R8UI:
+               case GL_R16I:
+               case GL_R16UI:
+               case GL_R32I:
+               case GL_R32UI:
+               case GL_RG8I:
+               case GL_RG8UI:
+               case GL_RG16I:
+               case GL_RG16UI:
+               case GL_RG32I:
+               case GL_RG32UI:
+               case GL_RGBA8I:
+               case GL_RGBA8UI:
+               case GL_RGBA16I:
+               case GL_RGBA16UI:
+               case GL_RGBA32I:
+               case GL_RGBA32UI:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+deUint32 getTypeForInternalFormat (deUint32 format)
+{
+       return glu::getTransferFormat(glu::mapGLInternalFormat(format)).dataType;
+}
+
+void genTexel (de::Random& rng, deUint32 glFormat, int texelBlockSize, const int texelCount, deUint8* buffer)
+{
+       if (isFloatFormat(glFormat))
+       {
+               const tcu::TextureFormat                format  = glu::mapGLInternalFormat(glFormat);
+               const tcu::PixelBufferAccess    access  (format, texelCount, 1, 1, buffer);
+               const tcu::TextureFormatInfo    info    = tcu::getTextureFormatInfo(format);
+
+               for (int texelNdx = 0; texelNdx < texelCount; texelNdx++)
+               {
+                       const float     red             = rng.getFloat(info.valueMin.x(), info.valueMax.x());
+                       const float green       = rng.getFloat(info.valueMin.y(), info.valueMax.y());
+                       const float blue        = rng.getFloat(info.valueMin.z(), info.valueMax.z());
+                       const float alpha       = rng.getFloat(info.valueMin.w(), info.valueMax.w());
+
+                       const Vec4      color   (red, green, blue, alpha);
+
+                       access.setPixel(color, texelNdx, 0, 0);
+               }
+       }
+       else if (isCompressedFormat(glFormat))
+       {
+               const tcu::CompressedTexFormat compressedFormat = glu::mapGLCompressedTexFormat(glFormat);
+
+               if (tcu::isAstcFormat(compressedFormat))
+               {
+                       const int               BLOCK_SIZE                              = 16;
+                       const deUint8   blocks[][BLOCK_SIZE]    =
+                       {
+                               // \note All of the following blocks are valid in LDR mode.
+                               { 252,  253,    255,    255,    255,    255,    255,    255,    8,              71,             90,             78,             22,             17,             26,             66,             },
+                               { 252,  253,    255,    255,    255,    255,    255,    255,    220,    74,             139,    235,    249,    6,              145,    125             },
+                               { 252,  253,    255,    255,    255,    255,    255,    255,    223,    251,    28,             206,    54,             251,    160,    174             },
+                               { 252,  253,    255,    255,    255,    255,    255,    255,    39,             4,              153,    219,    180,    61,             51,             37              },
+                               { 67,   2,              0,              254,    1,              0,              64,             215,    83,             211,    159,    105,    41,             140,    50,             2               },
+                               { 67,   130,    0,              170,    84,             255,    65,             215,    83,             211,    159,    105,    41,             140,    50,             2               },
+                               { 67,   2,              129,    38,             51,             229,    95,             215,    83,             211,    159,    105,    41,             140,    50,             2               },
+                               { 67,   130,    193,    56,             213,    144,    95,             215,    83,             211,    159,    105,    41,             140,    50,             2               }
+                       };
+
+                       DE_ASSERT(texelBlockSize == BLOCK_SIZE);
+
+                       for (int i = 0; i < texelCount; i++)
+                       {
+                               const int blockNdx = rng.getInt(0, DE_LENGTH_OF_ARRAY(blocks)-1);
+
+                               deMemcpy(buffer + i * BLOCK_SIZE,  blocks[blockNdx], BLOCK_SIZE);
+                       }
+               }
+               else
+               {
+                       for (int i = 0; i < texelBlockSize * texelCount; i++)
+                       {
+                               const deUint8 val = rng.getUint8();
+
+                               buffer[i] = val;
+                       }
+               }
+       }
+       else
+       {
+               for (int i = 0; i < texelBlockSize * texelCount; i++)
+               {
+                       const deUint8 val = rng.getUint8();
+
+                       buffer[i] = val;
+               }
+       }
+}
+
+IVec3 divRoundUp (const IVec3& a, const IVec3& b)
+{
+       IVec3 res;
+
+       for (int i =0; i < 3; i++)
+               res[i] = a[i] / b[i] + ((a[i] % b[i]) ? 1 : 0);
+
+       return res;
+}
+
+deUint32 mapFaceNdxToFace (int ndx)
+{
+       const deUint32 cubeFaces[] =
+       {
+               GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+               GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+
+               GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+               GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+
+               GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+               GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+       };
+
+       return de::getSizedArrayElement(cubeFaces, ndx);
+}
+
+deUint32 getFormatForInternalFormat (deUint32 format)
+{
+       return glu::getTransferFormat(glu::mapGLInternalFormat(format)).format;
+}
+
+void genericTexImage (const glw::Functions&    gl,
+                                         deUint32                              target,
+                                         int                                   faceNdx,
+                                         int                                   level,
+                                         const IVec3&                  size,
+                                         deUint32                              format,
+                                         size_t                                dataSize,
+                                         const void*                   data)
+{
+       const deUint32 glTarget = (target == GL_TEXTURE_CUBE_MAP ? mapFaceNdxToFace(faceNdx) : target);
+
+       DE_ASSERT(target == GL_TEXTURE_CUBE_MAP || faceNdx == 0);
+
+       if (isCompressedFormat(format))
+       {
+               switch (getTargetTexDims(target))
+               {
+                       case 2:
+                               DE_ASSERT(size.z() == 1);
+                               gl.compressedTexImage2D(glTarget, level, format, size.x(), size.y(), 0, dataSize, data);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D failed.");
+                               break;
+
+                       case 3:
+                               gl.compressedTexImage3D(glTarget, level, format, size.x(), size.y(), size.z(), 0, dataSize, data);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage3D failed.");
+                               break;
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+       else
+       {
+               const deUint32  glFormat        = getFormatForInternalFormat(format);
+               const deUint32  glType          = getTypeForInternalFormat(format);
+
+               switch (getTargetTexDims(target))
+               {
+                       case 2:
+                               DE_ASSERT(size.z() == 1);
+                               gl.texImage2D(glTarget, level, format, size.x(), size.y(), 0, glFormat, glType, data);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D failed.");
+                               break;
+
+                       case 3:
+                               gl.texImage3D(glTarget, level, format, size.x(), size.y(), size.z(), 0, glFormat, glType, data);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage3D failed.");
+                               break;
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+}
+
+void genTextureImage (const glw::Functions&                            gl,
+                                         de::Random&                                           rng,
+                                         deUint32                                                      name,
+                                         vector<ArrayBuffer<deUint8> >&        levels,
+                                         const ImageInfo&                                      info,
+                                         deUint32                                                      moreRestrictiveFormat)
+{
+       const int               texelBlockSize                  = getTexelBlockSize(info.getFormat());
+       const IVec3             texelBlockPixelSize     = getTexelBlockPixelSize(info.getFormat());
+       const IVec3             size                                    = info.getSize();
+
+       levels.resize(getLevelCount(info));
+
+       gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Setting pixel store aligment failed.");
+
+       gl.bindTexture(info.getTarget(), name);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Binding texture failed.");
+
+       for (int levelNdx = 0; levelNdx < getLevelCount(info); levelNdx++)
+       {
+               ArrayBuffer<deUint8>&   level                                   = levels[levelNdx];
+
+               const int                               faceCount                               = (info.getTarget() == GL_TEXTURE_CUBE_MAP ? 6 : 1);
+
+               const IVec3                             levelPixelSize                  = getLevelSize(info.getTarget(), info.getSize(), levelNdx);
+               const IVec3                             levelTexelBlockSize             = divRoundUp(levelPixelSize, texelBlockPixelSize);
+               const int                               levelTexelBlockCount    = levelTexelBlockSize.x() * levelTexelBlockSize.y() * levelTexelBlockSize.z();
+               const int                               levelSize                               = levelTexelBlockCount * texelBlockSize;
+
+               level.setStorage(levelSize * faceCount);
+
+               for (int faceNdx = 0; faceNdx < faceCount; faceNdx++)
+               {
+                       genTexel(rng, moreRestrictiveFormat, texelBlockSize, levelTexelBlockCount, level.getElementPtr(faceNdx * levelSize));
+
+                       genericTexImage(gl, info.getTarget(), faceNdx, levelNdx, levelPixelSize, info.getFormat(), levelSize, level.getElementPtr(faceNdx * levelSize));
+               }
+       }
+
+       gl.bindTexture(info.getTarget(), 0);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Unbinding texture failed.");
+}
+
+void genRenderbufferImage (const glw::Functions&                       gl,
+                                                  de::Random&                                          rng,
+                                                  deUint32                                                     name,
+                                                  vector<ArrayBuffer<deUint8> >&       levels,
+                                                  const ImageInfo&                                     info,
+                                                  deUint32                                                     moreRestrictiveFormat)
+{
+       const IVec3                                     size    = info.getSize();
+       const tcu::TextureFormat        format  = glu::mapGLInternalFormat(info.getFormat());
+
+       DE_ASSERT(info.getTarget() == GL_RENDERBUFFER);
+       DE_ASSERT(info.getSize().z() == 1);
+       DE_ASSERT(getLevelCount(info) == 1);
+       DE_ASSERT(!isCompressedFormat(info.getFormat()));
+
+       glu::Framebuffer framebuffer(gl);
+
+       levels.resize(1);
+       levels[0].setStorage(format.getPixelSize() * size.x() * size.y());
+       tcu::PixelBufferAccess refAccess(format, size.x(), size.y(), 1, levels[0].getPtr());
+
+       gl.bindRenderbuffer(GL_RENDERBUFFER, name);
+       gl.renderbufferStorage(GL_RENDERBUFFER, info.getFormat(), info.getSize().x(), info.getSize().y());
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Binding and setting storage for renderbuffer failed.");
+
+       gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
+       gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, name);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Binding framebuffer and attaching renderbuffer failed.");
+
+       {
+               vector<deUint8> texelBlock(format.getPixelSize());
+
+               genTexel(rng, moreRestrictiveFormat, format.getPixelSize(), 1, &(texelBlock[0]));
+
+               {
+                       const tcu::ConstPixelBufferAccess texelAccess (format, 1, 1, 1, &(texelBlock[0]));
+
+                       if (isFloatFormat(info.getFormat()))
+                       {
+                               const tcu::Vec4 color = texelAccess.getPixel(0, 0, 0);
+
+                               gl.clearBufferfv(GL_COLOR, 0, (const float*)&color);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
+
+                               tcu::clear(refAccess, color);
+                       }
+                       else if (isIntFormat(info.getFormat()))
+                       {
+                               const tcu::IVec4 color = texelAccess.getPixelInt(0, 0, 0);
+
+                               gl.clearBufferiv(GL_COLOR, 0, (const deInt32*)&color);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
+
+                               tcu::clear(refAccess, color);
+                       }
+                       else if (isUintFormat(info.getFormat()))
+                       {
+                               const tcu::IVec4 color = texelAccess.getPixelInt(0, 0, 0);
+
+                               gl.clearBufferuiv(GL_COLOR, 0, (const deUint32*)&color);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
+
+                               tcu::clear(refAccess, color);
+                       }
+                       else
+                       {
+                               const tcu::Vec4 color = texelAccess.getPixel(0, 0, 0);
+
+                               gl.clearColor(color.x(), color.y(), color.z(), color.w());
+                               gl.clear(GL_COLOR_BUFFER_BIT);
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
+
+                               tcu::clear(refAccess, color);
+                       }
+               }
+       }
+
+       gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
+       gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unbind renderbufer and framebuffer.");
+}
+
+
+
+void genImage (const glw::Functions&                   gl,
+                          de::Random&                                          rng,
+                          deUint32                                                     name,
+                          vector<ArrayBuffer<deUint8> >&       levels,
+                          const ImageInfo&                                     info,
+                          deUint32                                                     moreRestrictiveFormat)
+{
+       if (isTextureTarget(info.getTarget()))
+               genTextureImage(gl, rng, name, levels, info, moreRestrictiveFormat);
+       else
+               genRenderbufferImage(gl, rng, name, levels, info, moreRestrictiveFormat);
+}
+
+IVec3 getTexelBlockStride (const ImageInfo& info, int level)
+{
+       const IVec3     size                                    = getLevelSize(info.getTarget(), info.getSize(), level);
+       const int       texelBlockSize                  = getTexelBlockSize(info.getFormat());
+       const IVec3 texelBlockPixelSize         = getTexelBlockPixelSize(info.getFormat());
+       const IVec3 textureTexelBlockSize       = divRoundUp(size, texelBlockPixelSize);
+
+       return IVec3(texelBlockSize, textureTexelBlockSize.x() * texelBlockSize, textureTexelBlockSize.x() * textureTexelBlockSize.y() * texelBlockSize);
+}
+
+int sumComponents (const IVec3& v)
+{
+       int s = 0;
+
+       for (int i = 0; i < 3; i++)
+               s += v[i];
+
+       return s;
+}
+
+void copyImageData (vector<ArrayBuffer<deUint8> >&                     dstImageData,
+                                   const ImageInfo&                                            dstImageInfo,
+                                       int                                                                             dstLevel,
+                                       const IVec3&                                                    dstPos,
+
+                                       const vector<ArrayBuffer<deUint8> >&    srcImageData,
+                                   const ImageInfo&                                            srcImageInfo,
+                                       int                                                                             srcLevel,
+                                       const IVec3&                                                    srcPos,
+
+                                       const IVec3&                                                    copySize)
+{
+       const ArrayBuffer<deUint8>&     srcLevelData                    = srcImageData[srcLevel];
+       ArrayBuffer<deUint8>&           dstLevelData                    = dstImageData[dstLevel];
+
+       const IVec3                                     srcTexelBlockPixelSize  = getTexelBlockPixelSize(srcImageInfo.getFormat());
+       const int                                       srcTexelBlockSize               = getTexelBlockSize(srcImageInfo.getFormat());
+       const IVec3                                     srcTexelPos                             = srcPos / srcTexelBlockPixelSize;
+       const IVec3                                     srcTexelBlockStride             = getTexelBlockStride(srcImageInfo, srcLevel);
+
+       const IVec3                                     dstTexelBlockPixelSize  = getTexelBlockPixelSize(dstImageInfo.getFormat());
+       const int                                       dstTexelBlockSize               = getTexelBlockSize(dstImageInfo.getFormat());
+       const IVec3                                     dstTexelPos                             = dstPos / dstTexelBlockPixelSize;
+       const IVec3                                     dstTexelBlockStride             = getTexelBlockStride(dstImageInfo, dstLevel);
+
+       const IVec3                                     copyTexelBlockCount             = copySize / srcTexelBlockPixelSize;
+       const int                                       texelBlockSize                  = srcTexelBlockSize;
+
+       DE_ASSERT(srcTexelBlockSize == dstTexelBlockSize);
+       DE_UNREF(dstTexelBlockSize);
+
+       DE_ASSERT((copySize.x() % srcTexelBlockPixelSize.x()) == 0);
+       DE_ASSERT((copySize.y() % srcTexelBlockPixelSize.y()) == 0);
+       DE_ASSERT((copySize.z() % srcTexelBlockPixelSize.z()) == 0);
+
+       DE_ASSERT((srcPos.x() % srcTexelBlockPixelSize.x()) == 0);
+       DE_ASSERT((srcPos.y() % srcTexelBlockPixelSize.y()) == 0);
+       DE_ASSERT((srcPos.z() % srcTexelBlockPixelSize.z()) == 0);
+
+       for (int z = 0; z < copyTexelBlockCount.z(); z++)
+       for (int y = 0; y < copyTexelBlockCount.y(); y++)
+       {
+               const IVec3                             blockPos                (0, y, z);
+               const deUint8* const    srcPtr                  = srcLevelData.getElementPtr(sumComponents((srcTexelPos + blockPos) * srcTexelBlockStride));
+               deUint8* const                  dstPtr                  = dstLevelData.getElementPtr(sumComponents((dstTexelPos + blockPos) * dstTexelBlockStride));
+               const int                               copyLineSize    = copyTexelBlockCount.x() * texelBlockSize;
+
+               deMemcpy(dstPtr, srcPtr, copyLineSize);
+       }
+}
+
+vector<tcu::ConstPixelBufferAccess> getLevelAccesses (const vector<ArrayBuffer<deUint8> >& data, const ImageInfo& info)
+{
+       const tcu::TextureFormat                        format  = glu::mapGLInternalFormat(info.getFormat());
+       const IVec3                                                     size    = info.getSize();
+
+       vector<tcu::ConstPixelBufferAccess>     result;
+
+       DE_ASSERT((int)data.size() == getLevelCount(info));
+
+       for (int level = 0; level < (int)data.size(); level++)
+       {
+               const IVec3 levelSize = getLevelSize(info.getTarget(), size, level);
+
+               result.push_back(tcu::ConstPixelBufferAccess(format, levelSize.x(), levelSize.y(), levelSize.z(), data[level].getPtr()));
+       }
+
+       return result;
+}
+
+vector<tcu::ConstPixelBufferAccess> getCubeLevelAccesses (const vector<ArrayBuffer<deUint8> >& data,
+                                                                                                                 const ImageInfo&                                              info,
+                                                                                                                 int                                                                   faceNdx)
+{
+       const tcu::TextureFormat                        format                          = glu::mapGLInternalFormat(info.getFormat());
+       const IVec3                                                     size                            = info.getSize();
+       const int                                                       texelBlockSize          = getTexelBlockSize(info.getFormat());
+       const IVec3                                                     texelBlockPixelSize = getTexelBlockPixelSize(info.getFormat());
+       vector<tcu::ConstPixelBufferAccess>     result;
+
+       DE_ASSERT(info.getTarget() == GL_TEXTURE_CUBE_MAP);
+       DE_ASSERT((int)data.size() == getLevelCount(info));
+
+       for (int level = 0; level < (int)data.size(); level++)
+       {
+               const IVec3 levelPixelSize                      = getLevelSize(info.getTarget(), size, level);
+               const IVec3     levelTexelBlockSize             = divRoundUp(levelPixelSize, texelBlockPixelSize);
+               const int       levelTexelBlockCount    = levelTexelBlockSize.x() * levelTexelBlockSize.y() * levelTexelBlockSize.z();
+               const int       levelSize                               = levelTexelBlockCount * texelBlockSize;
+
+               result.push_back(tcu::ConstPixelBufferAccess(format, levelPixelSize.x(), levelPixelSize.y(), levelPixelSize.z(), data[level].getElementPtr(levelSize * faceNdx)));
+       }
+
+       return result;
+}
+
+void copyImage (const glw::Functions&                                  gl,
+
+                               deUint32                                                                dstName,
+                               vector<ArrayBuffer<deUint8> >&                  dstImageData,
+                               const ImageInfo&                                                dstImageInfo,
+                               int                                                                             dstLevel,
+                               const IVec3&                                                    dstPos,
+
+                               deUint32                                                                srcName,
+                               const vector<ArrayBuffer<deUint8> >&    srcImageData,
+                               const ImageInfo&                                                srcImageInfo,
+                               int                                                                             srcLevel,
+                               const IVec3&                                                    srcPos,
+
+                               const IVec3&                                                    copySize)
+{
+       gl.copyImageSubData(srcName, srcImageInfo.getTarget(), srcLevel, srcPos.x(), srcPos.y(), srcPos.z(),
+                                               dstName, dstImageInfo.getTarget(), dstLevel, dstPos.x(), dstPos.y(), dstPos.z(),
+                                               copySize.x(), copySize.y(), copySize.z());
+
+       GLU_EXPECT_NO_ERROR(gl.getError(), "glCopyImageSubData failed.");
+
+       copyImageData(dstImageData, dstImageInfo, dstLevel, dstPos,
+                                 srcImageData, srcImageInfo, srcLevel, srcPos, copySize);
+}
+
+void verifyTexture2DView (tcu::TestContext&                    testContext,
+                                                 glu::RenderContext&           renderContext,
+                                                 TextureRenderer&                      renderer,
+                                                 tcu::ResultCollector&         results,
+                                                 de::Random&                           rng,
+                                                 deUint32                                      name,
+                                                 const ImageInfo&                      info,
+                                                 const tcu::Texture2DView&     refTexture)
+{
+       tcu::TestLog&                                   log                             = testContext.getLog();
+       const glw::Functions&                   gl                              = renderContext.getFunctions();
+       const tcu::RGBA                                 threshold               = renderContext.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
+       const tcu::TextureFormat                format                  = refTexture.getLevel(0).getFormat();
+       const tcu::TextureFormatInfo    spec                    = tcu::getTextureFormatInfo(format);
+
+       ReferenceParams                                 renderParams    (TEXTURETYPE_2D);
+
+       renderParams.samplerType        = getSamplerType(format);
+       renderParams.sampler            = Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST_MIPMAP_NEAREST, Sampler::NEAREST);
+       renderParams.colorScale         = spec.lookupScale;
+       renderParams.colorBias          = spec.lookupBias;
+
+       gl.activeTexture(GL_TEXTURE0);
+       gl.bindTexture(GL_TEXTURE_2D, name);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind texture.");
+
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup texture filtering state.");
+
+       for (int level = 0; level < getLevelCount(info); level++)
+       {
+               const IVec3                             levelSize               = getLevelSize(info.getTarget(), info.getSize(), level);
+               const RandomViewport    viewport                (renderContext.getRenderTarget(), levelSize.x(), levelSize.y(), rng.getUint32());
+
+               vector<float>                   texCoord;
+               tcu::Surface                    renderedFrame   (viewport.width, viewport.height);
+               tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
+
+               computeQuadTexCoord2D(texCoord, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f));
+
+               // Setup base viewport.
+               gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+               // Draw.
+               renderer.renderQuad(0, &texCoord[0], renderParams);
+               glu::readPixels(renderContext, viewport.x, viewport.y, renderedFrame.getAccess());
+               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render and read pixels.");
+
+               // Compute reference.
+               sampleTexture(SurfaceAccess(referenceFrame, renderContext.getRenderTarget().getPixelFormat()), refTexture, &texCoord[0], renderParams);
+
+               // Compare and log.
+               if (!pixelThresholdCompare(log, ("Level" + de::toString(level)).c_str(), ("Render level " + de::toString(level)).c_str(), referenceFrame, renderedFrame, threshold, tcu::COMPARE_LOG_ON_ERROR))
+                       results.fail("Image comparison of level " + de::toString(level) + " failed.");
+               else
+                       log << TestLog::Message << "Image comparison of level " << level << " passed." << TestLog::EndMessage;
+       }
+
+       gl.bindTexture(GL_TEXTURE_2D, 0);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unbind texture.");
+}
+
+void decompressTextureLevel (const tcu::TexDecompressionParams&                params,
+                                                        ArrayBuffer<deUint8>&                                  levelData,
+                                                        tcu::PixelBufferAccess&                                levelAccess,
+                                                        const tcu::CompressedTexFormat&                compressedFormat,
+                                                        const tcu::TextureFormat&                              decompressedFormat,
+                                                        const IVec3&                                                   levelPixelSize,
+                                                        const void*                                                    data)
+{
+       levelData.setStorage(levelPixelSize.x() * levelPixelSize.y() * levelPixelSize.z() * decompressedFormat.getPixelSize());
+       levelAccess = tcu::PixelBufferAccess(decompressedFormat, levelPixelSize.x(), levelPixelSize.y(), levelPixelSize.z(), levelData.getPtr());
+
+       tcu::decompress(levelAccess, compressedFormat, (const deUint8*)data, params);
+}
+
+void decompressTexture (vector<ArrayBuffer<deUint8> >&                 levelDatas,
+                                               vector<tcu::PixelBufferAccess>&                 levelAccesses,
+                                               glu::RenderContext&                                             renderContext,
+                                               const ImageInfo&                                                info,
+                                               const vector<ArrayBuffer<deUint8> >&    data)
+{
+       const tcu::CompressedTexFormat  compressedFormat        = glu::mapGLCompressedTexFormat(info.getFormat());
+       const tcu::TextureFormat                decompressedFormat      = tcu::getUncompressedFormat(compressedFormat);
+       const IVec3                                             size                            = info.getSize();
+       de::UniquePtr<glu::ContextInfo> ctxInfo                         (glu::ContextInfo::create(renderContext));
+       tcu::TexDecompressionParams             decompressParams;
+
+       if (tcu::isAstcFormat(compressedFormat))
+       {
+               if (ctxInfo->isExtensionSupported("GL_KHR_texture_compression_astc_hdr"))
+                       decompressParams = tcu::TexDecompressionParams(tcu::TexDecompressionParams::ASTCMODE_HDR);
+               else if (ctxInfo->isExtensionSupported("GL_KHR_texture_compression_astc_ldr"))
+                       decompressParams = tcu::TexDecompressionParams(tcu::TexDecompressionParams::ASTCMODE_LDR);
+               else
+                       DE_ASSERT(false);
+       }
+
+       levelDatas.resize(getLevelCount(info));
+       levelAccesses.resize(getLevelCount(info));
+
+       for (int level = 0; level < getLevelCount(info); level++)
+       {
+               const IVec3                                     levelPixelSize  = getLevelSize(info.getTarget(), size, level);
+               de::ArrayBuffer<deUint8>&       levelData               = levelDatas[level];
+               tcu::PixelBufferAccess&         levelAccess     = levelAccesses[level];
+
+               decompressTextureLevel(decompressParams, levelData, levelAccess, compressedFormat, decompressedFormat, levelPixelSize, data[level].getPtr());
+       }
+}
+
+void verifyTexture2D (tcu::TestContext&                                                testContext,
+                                         glu::RenderContext&                                   renderContext,
+                                         TextureRenderer&                                              textureRenderer,
+                                         tcu::ResultCollector&                                 results,
+                                         de::Random&                                                   rng,
+                                         deUint32                                                              name,
+                                         const vector<ArrayBuffer<deUint8> >&  data,
+                                         const ImageInfo&                                              info)
+{
+       if (isCompressedFormat(info.getFormat()))
+       {
+               vector<de::ArrayBuffer<deUint8> >       levelDatas;
+               vector<tcu::PixelBufferAccess>          levelAccesses;
+
+               decompressTexture(levelDatas, levelAccesses, renderContext, info, data);
+
+               {
+                       const tcu::Texture2DView refTexture(levelAccesses.size(), &(levelAccesses[0]));
+
+                       verifyTexture2DView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+               }
+       }
+       else
+       {
+               const vector<tcu::ConstPixelBufferAccess>       levelAccesses   = getLevelAccesses(data, info);
+               const tcu::Texture2DView                                        refTexture              (levelAccesses.size(), &(levelAccesses[0]));
+
+               verifyTexture2DView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+       }
+}
+
+void verifyTexture3DView (tcu::TestContext&                    testContext,
+                                                 glu::RenderContext&           renderContext,
+                                                 TextureRenderer&                      renderer,
+                                                 tcu::ResultCollector&         results,
+                                                 de::Random&                           rng,
+                                                 deUint32                                      name,
+                                                 const ImageInfo&                      info,
+                                                 const tcu::Texture3DView&     refTexture)
+{
+       tcu::TestLog&                                   log                             = testContext.getLog();
+       const glw::Functions&                   gl                              = renderContext.getFunctions();
+       const tcu::RGBA                                 threshold               = renderContext.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
+       const tcu::TextureFormat                format                  = refTexture.getLevel(0).getFormat();
+       const tcu::TextureFormatInfo    spec                    = tcu::getTextureFormatInfo(format);
+
+       ReferenceParams                                 renderParams    (TEXTURETYPE_3D);
+
+       renderParams.samplerType        = getSamplerType(format);
+       renderParams.sampler            = Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST_MIPMAP_NEAREST, Sampler::NEAREST);
+       renderParams.colorScale         = spec.lookupScale;
+       renderParams.colorBias          = spec.lookupBias;
+
+       gl.activeTexture(GL_TEXTURE0);
+       gl.bindTexture(GL_TEXTURE_3D, name);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind texture.");
+
+       gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+       gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup texture filtering state.");
+
+       for (int level = 0; level < getLevelCount(info); level++)
+       {
+               const IVec3 levelSize = getLevelSize(info.getTarget(), info.getSize(), level);
+
+               for (int slice = 0; slice < levelSize.z(); slice++)
+               {
+                       const RandomViewport    viewport                (renderContext.getRenderTarget(), levelSize.x(), levelSize.y(), rng.getUint32());
+                       const float                             r                               = (float(slice) + 0.5f) / levelSize.z();
+                       tcu::Surface                    renderedFrame   (viewport.width, viewport.height);
+                       tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
+                       vector<float>                   texCoord;
+
+                       computeQuadTexCoord3D(texCoord, tcu::Vec3(0.0f, 0.0f, r), tcu::Vec3(1.0f, 1.0f, r), tcu::IVec3(0, 1, 2));
+
+                       // Setup base viewport.
+                       gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+                       // Draw.
+                       renderer.renderQuad(0, &texCoord[0], renderParams);
+                       glu::readPixels(renderContext, viewport.x, viewport.y, renderedFrame.getAccess());
+                       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render and read pixels.");
+
+                       // Compute reference.
+                       sampleTexture(SurfaceAccess(referenceFrame, renderContext.getRenderTarget().getPixelFormat()), refTexture, &texCoord[0], renderParams);
+
+                       // Compare and log.
+                       if (!pixelThresholdCompare(log, ("Level" + de::toString(level) + "Slice" + de::toString(slice)).c_str(), ("Render level " + de::toString(level) + ", Slice" + de::toString(slice)).c_str(), referenceFrame, renderedFrame, threshold, tcu::COMPARE_LOG_ON_ERROR))
+                               results.fail("Image comparison of level " + de::toString(level) + " and slice " + de::toString(slice) + " failed.");
+                       else
+                               log << TestLog::Message << "Image comparison of level " << level << " and slice " << slice << " passed." << TestLog::EndMessage;;
+               }
+       }
+
+       gl.bindTexture(GL_TEXTURE_3D, 0);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unbind texture.");
+}
+
+void verifyTexture3D (tcu::TestContext&                                                testContext,
+                                         glu::RenderContext&                                   renderContext,
+                                         TextureRenderer&                                              textureRenderer,
+                                         tcu::ResultCollector&                                 results,
+                                         de::Random&                                                   rng,
+                                         deUint32                                                              name,
+                                         const vector<ArrayBuffer<deUint8> >&  data,
+                                         const ImageInfo&                                              info)
+{
+       if (isCompressedFormat(info.getFormat()))
+       {
+               vector<de::ArrayBuffer<deUint8> >       levelDatas;
+               vector<tcu::PixelBufferAccess>          levelAccesses;
+
+               decompressTexture(levelDatas, levelAccesses, renderContext, info, data);
+
+               {
+                       const tcu::Texture3DView refTexture(levelAccesses.size(), &(levelAccesses[0]));
+
+                       verifyTexture3DView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+               }
+       }
+       else
+       {
+               const vector<tcu::ConstPixelBufferAccess>       levelAccesses   = getLevelAccesses(data, info);
+               const tcu::Texture3DView                                        refTexture              (levelAccesses.size(), &(levelAccesses[0]));
+
+               verifyTexture3DView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+       }
+}
+
+void verifyTextureCubemapView (tcu::TestContext&                       testContext,
+                                                          glu::RenderContext&                  renderContext,
+                                                          TextureRenderer&                             renderer,
+                                                          tcu::ResultCollector&                results,
+                                                          de::Random&                                  rng,
+                                                          deUint32                                             name,
+                                                          const ImageInfo&                             info,
+                                                          const tcu::TextureCubeView&  refTexture)
+{
+       tcu::TestLog&                                   log                             = testContext.getLog();
+       const glw::Functions&                   gl                              = renderContext.getFunctions();
+       const tcu::RGBA                                 threshold               = renderContext.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
+       const tcu::TextureFormat                format                  = refTexture.getLevelFace(0, tcu::CUBEFACE_POSITIVE_X).getFormat();
+       const tcu::TextureFormatInfo    spec                    = tcu::getTextureFormatInfo(format);
+
+       ReferenceParams                                 renderParams    (TEXTURETYPE_CUBE);
+
+       renderParams.samplerType        = getSamplerType(format);
+       renderParams.sampler            = Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST_MIPMAP_NEAREST, Sampler::NEAREST);
+       renderParams.colorScale         = spec.lookupScale;
+       renderParams.colorBias          = spec.lookupBias;
+
+       gl.activeTexture(GL_TEXTURE0);
+       gl.bindTexture(GL_TEXTURE_CUBE_MAP, name);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind texture.");
+
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup texture filtering state.");
+
+       for (int level = 0; level < getLevelCount(info); level++)
+       {
+               const IVec3 levelSize = getLevelSize(info.getTarget(), info.getSize(), level);
+
+               // \note It seems we can't reliably sample two smallest texture levels with cubemaps
+               if (levelSize.x() < 4 && levelSize.y() < 4)
+                       continue;
+
+               for (int face = 0; face < 6; face++)
+               {
+                       const RandomViewport    viewport                (renderContext.getRenderTarget(), levelSize.x(), levelSize.y(), rng.getUint32());
+                       const string                    cubemapFaceName = glu::getCubeMapFaceStr(mapFaceNdxToFace(face)).toString();
+                       tcu::Surface                    renderedFrame   (viewport.width, viewport.height);
+                       tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
+                       vector<float>                   texCoord;
+
+                       computeQuadTexCoordCube(texCoord, glu::getCubeFaceFromGL(mapFaceNdxToFace(face)));
+
+                       // Setup base viewport.
+                       gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+                       // Draw.
+                       renderer.renderQuad(0, &texCoord[0], renderParams);
+                       glu::readPixels(renderContext, viewport.x, viewport.y, renderedFrame.getAccess());
+                       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render and read pixels.");
+
+                       // Compute reference.
+                       sampleTexture(SurfaceAccess(referenceFrame, renderContext.getRenderTarget().getPixelFormat()), refTexture, &texCoord[0], renderParams);
+
+                       // Compare and log.
+                       if (!pixelThresholdCompare(log, ("Level" + de::toString(level) + "Face" + cubemapFaceName).c_str(), ("Render level " + de::toString(level) + ", Face " + cubemapFaceName).c_str(), referenceFrame, renderedFrame, threshold, tcu::COMPARE_LOG_ON_ERROR))
+                               results.fail("Image comparison of level " + de::toString(level) + " and face " + cubemapFaceName + " failed.");
+                       else
+                               log << TestLog::Message << "Image comparison of level " << level << " and face " << cubemapFaceName << " passed." << TestLog::EndMessage;
+               }
+       }
+
+       gl.bindTexture(GL_TEXTURE_CUBE_MAP, 0);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unbind texture.");
+}
+
+void verifyTextureCubemap (tcu::TestContext&                                   testContext,
+                                                  glu::RenderContext&                                  renderContext,
+                                                  TextureRenderer&                                             textureRenderer,
+                                                  tcu::ResultCollector&                                results,
+                                                  de::Random&                                                  rng,
+                                                  deUint32                                                             name,
+                                                  const vector<ArrayBuffer<deUint8> >& data,
+                                                  const ImageInfo&                                             info)
+{
+       if (isCompressedFormat(info.getFormat()))
+       {
+               const tcu::CompressedTexFormat& compressedFormat        = glu::mapGLCompressedTexFormat(info.getFormat());
+               const tcu::TextureFormat&               decompressedFormat      = tcu::getUncompressedFormat(compressedFormat);
+
+               const int                                               texelBlockSize          = getTexelBlockSize(info.getFormat());
+               const IVec3                                             texelBlockPixelSize = getTexelBlockPixelSize(info.getFormat());
+
+               vector<tcu::PixelBufferAccess>  levelAccesses[6];
+               vector<ArrayBuffer<deUint8> >   levelDatas[6];
+               de::UniquePtr<glu::ContextInfo> ctxInfo                         (glu::ContextInfo::create(renderContext));
+               tcu::TexDecompressionParams             decompressParams;
+
+               if (tcu::isAstcFormat(compressedFormat))
+               {
+                       if (ctxInfo->isExtensionSupported("GL_KHR_texture_compression_astc_hdr"))
+                               decompressParams = tcu::TexDecompressionParams(tcu::TexDecompressionParams::ASTCMODE_HDR);
+                       else if (ctxInfo->isExtensionSupported("GL_KHR_texture_compression_astc_ldr"))
+                               decompressParams = tcu::TexDecompressionParams(tcu::TexDecompressionParams::ASTCMODE_LDR);
+                       else
+                               DE_ASSERT(false);
+               }
+
+               for (int faceNdx = 0; faceNdx < 6; faceNdx++)
+               {
+                       levelAccesses[faceNdx].resize(getLevelCount(info));
+                       levelDatas[faceNdx].resize(getLevelCount(info));
+               }
+
+               for (int level = 0; level < getLevelCount(info); level++)
+               {
+                       for (int faceNdx = 0; faceNdx < 6; faceNdx++)
+                       {
+                               const IVec3                             levelPixelSize                  = getLevelSize(info.getTarget(), info.getSize(), level);
+                               const IVec3                             levelTexelBlockSize             = divRoundUp(levelPixelSize, texelBlockPixelSize);
+                               const int                               levelTexelBlockCount    = levelTexelBlockSize.x() * levelTexelBlockSize.y() * levelTexelBlockSize.z();
+                               const int                               levelSize                               = levelTexelBlockCount * texelBlockSize;
+
+                               const deUint8*                  dataPtr                                 = data[level].getElementPtr(faceNdx * levelSize);
+                               tcu::PixelBufferAccess& levelAccess                             = levelAccesses[faceNdx][level];
+                               ArrayBuffer<deUint8>&   levelData                               = levelDatas[faceNdx][level];
+
+                               decompressTextureLevel(decompressParams, levelData, levelAccess, compressedFormat, decompressedFormat, levelPixelSize, dataPtr);
+                       }
+               }
+
+               const tcu::ConstPixelBufferAccess* levels[6];
+
+               for (int faceNdx = 0; faceNdx < 6; faceNdx++)
+                       levels[glu::getCubeFaceFromGL(mapFaceNdxToFace(faceNdx))] = &(levelAccesses[faceNdx][0]);
+
+               {
+                       const tcu::TextureCubeView refTexture(getLevelCount(info), levels);
+
+                       verifyTextureCubemapView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+               }
+       }
+       else
+       {
+               const vector<tcu::ConstPixelBufferAccess> levelAccesses[6] =
+               {
+                       getCubeLevelAccesses(data, info, 0),
+                       getCubeLevelAccesses(data, info, 1),
+                       getCubeLevelAccesses(data, info, 2),
+                       getCubeLevelAccesses(data, info, 3),
+                       getCubeLevelAccesses(data, info, 4),
+                       getCubeLevelAccesses(data, info, 5),
+               };
+
+               const tcu::ConstPixelBufferAccess* levels[6];
+
+               for (int faceNdx = 0; faceNdx < 6; faceNdx++)
+                       levels[glu::getCubeFaceFromGL(mapFaceNdxToFace(faceNdx))] = &(levelAccesses[faceNdx][0]);
+
+               {
+                       const tcu::TextureCubeView refTexture(getLevelCount(info), levels);
+
+                       verifyTextureCubemapView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+               }
+       }
+}
+
+void verifyTexture2DArrayView (tcu::TestContext&                               testContext,
+                                                          glu::RenderContext&                          renderContext,
+                                                          TextureRenderer&                                     renderer,
+                                                          tcu::ResultCollector&                        results,
+                                                          de::Random&                                          rng,
+                                                          deUint32                                                     name,
+                                                          const ImageInfo&                                     info,
+                                                          const tcu::Texture2DArrayView&       refTexture)
+{
+       tcu::TestLog&                                   log                             = testContext.getLog();
+       const glw::Functions&                   gl                              = renderContext.getFunctions();
+       const tcu::RGBA                                 threshold               = renderContext.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
+       const tcu::TextureFormat                format                  = refTexture.getLevel(0).getFormat();
+       const tcu::TextureFormatInfo    spec                    = tcu::getTextureFormatInfo(format);
+
+       ReferenceParams                                 renderParams    (TEXTURETYPE_2D_ARRAY);
+
+       renderParams.samplerType        = getSamplerType(format);
+       renderParams.sampler            = Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST_MIPMAP_NEAREST, Sampler::NEAREST);
+       renderParams.colorScale         = spec.lookupScale;
+       renderParams.colorBias          = spec.lookupBias;
+
+       gl.activeTexture(GL_TEXTURE0);
+       gl.bindTexture(GL_TEXTURE_2D_ARRAY, name);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind texture.");
+
+       gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+       gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup texture filtering state.");
+
+       for (int level = 0; level < getLevelCount(info); level++)
+       {
+               const IVec3 levelSize = getLevelSize(info.getTarget(), info.getSize(), level);
+
+               for (int layer = 0; layer < levelSize.z(); layer++)
+               {
+                       const RandomViewport    viewport                (renderContext.getRenderTarget(), levelSize.x(), levelSize.y(), rng.getUint32());
+                       tcu::Surface                    renderedFrame   (viewport.width, viewport.height);
+                       tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
+                       vector<float>                   texCoord;
+
+                       computeQuadTexCoord2DArray(texCoord, layer, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f));
+
+                       // Setup base viewport.
+                       gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+                       // Draw.
+                       renderer.renderQuad(0, &texCoord[0], renderParams);
+                       glu::readPixels(renderContext, viewport.x, viewport.y, renderedFrame.getAccess());
+                       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render and read pixels.");
+
+                       // Compute reference.
+                       sampleTexture(SurfaceAccess(referenceFrame, renderContext.getRenderTarget().getPixelFormat()), refTexture, &texCoord[0], renderParams);
+
+                       // Compare and log.
+                       if (!pixelThresholdCompare(log, ("Level" + de::toString(level) + "Layer" + de::toString(layer)).c_str(), ("Render level " + de::toString(level) + ", Layer" + de::toString(layer)).c_str(), referenceFrame, renderedFrame, threshold, tcu::COMPARE_LOG_ON_ERROR))
+                               results.fail("Image comparison of level " + de::toString(level) + " and layer " + de::toString(layer) + " failed.");
+                       else
+                               log << TestLog::Message << "Image comparison of level " << level << " and layer " << layer << " passed." << TestLog::EndMessage;
+               }
+       }
+
+       gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unbind texture.");
+}
+
+void verifyTexture2DArray (tcu::TestContext&                                   testContext,
+                                                  glu::RenderContext&                                  renderContext,
+                                                  TextureRenderer&                                             textureRenderer,
+                                                  tcu::ResultCollector&                                results,
+                                                  de::Random&                                                  rng,
+                                                  deUint32                                                             name,
+                                                  const vector<ArrayBuffer<deUint8> >& data,
+                                                  const ImageInfo&                                             info)
+{
+       if (isCompressedFormat(info.getFormat()))
+       {
+               vector<de::ArrayBuffer<deUint8> >       levelDatas;
+               vector<tcu::PixelBufferAccess>          levelAccesses;
+
+               decompressTexture(levelDatas, levelAccesses, renderContext, info, data);
+
+               {
+                       const tcu::Texture2DArrayView refTexture(levelAccesses.size(), &(levelAccesses[0]));
+
+                       verifyTexture2DArrayView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+               }
+       }
+       else
+       {
+               const vector<tcu::ConstPixelBufferAccess>       levelAccesses   = getLevelAccesses(data, info);
+               const tcu::Texture2DArrayView                           refTexture              (levelAccesses.size(), &(levelAccesses[0]));
+
+               verifyTexture2DArrayView(testContext, renderContext, textureRenderer, results, rng, name, info, refTexture);
+       }
+}
+
+tcu::TextureFormat getReadPixelFormat (const tcu::TextureFormat& format)
+{
+       switch (tcu::getTextureChannelClass(format.type))
+       {
+               case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+               case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+
+               case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
+
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
+
+               default:
+                       DE_ASSERT(false);
+                       return tcu::TextureFormat();
+       }
+}
+
+Vec4 calculateThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
+{
+       DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
+       DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
+
+       DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
+       DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
+
+       DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
+       DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
+
+       {
+               const tcu::IVec4        srcBits         = tcu::getTextureFormatBitDepth(sourceFormat);
+               const tcu::IVec4        readBits        = tcu::getTextureFormatBitDepth(readPixelsFormat);
+
+               return Vec4(1.0f) / ((tcu::IVec4(1) << (tcu::min(srcBits, readBits))) - tcu::IVec4(1)).cast<float>();
+       }
+}
+
+void verifyRenderbuffer (tcu::TestContext&                                             testContext,
+                                                glu::RenderContext&                                    renderContext,
+                                                tcu::ResultCollector&                                  results,
+                                                deUint32                                                               name,
+                                                const vector<ArrayBuffer<deUint8> >&   data,
+                                                const ImageInfo&                                               info)
+{
+       const glw::Functions&                           gl                                      = renderContext.getFunctions();
+       TestLog&                                                        log                                     = testContext.getLog();
+
+       const tcu::TextureFormat                        format                          = glu::mapGLInternalFormat(info.getFormat());
+       const IVec3                                                     size                            = info.getSize();
+       const tcu::ConstPixelBufferAccess       refRenderbuffer         (format, size.x(), size.y(), 1, data[0].getPtr());
+       const tcu::TextureFormat                        readPixelsFormat        = getReadPixelFormat(format);
+       tcu::TextureLevel                                       renderbuffer            (readPixelsFormat, size.x(), size.y());
+
+       DE_ASSERT(size.z() == 1);
+       DE_ASSERT(data.size() == 1);
+
+       {
+               glu::Framebuffer framebuffer(gl);
+
+               gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create and bind framebuffer.");
+
+               gl.bindRenderbuffer(GL_RENDERBUFFER, name);
+               gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, name);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind and attach renderbuffer to framebuffer.");
+
+               glu::readPixels(renderContext, 0, 0, renderbuffer.getAccess());
+
+               gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
+               gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unbind renderbuffer and framebuffer.");
+       }
+
+       if (isFloatFormat(info.getFormat()))
+       {
+               const tcu::UVec4 threshold (2, 2, 2, 2);
+
+               if (!(tcu::floatUlpThresholdCompare(log, "Image comparison", "Image comparison", refRenderbuffer, renderbuffer.getAccess(), threshold, tcu::COMPARE_LOG_ON_ERROR)))
+                       results.fail("Image comparison failed.");
+               else
+                       log << TestLog::Message << "Image comarison passed." << TestLog::EndMessage;
+       }
+       else if (isIntFormat(info.getFormat()) || isUintFormat(info.getFormat()))
+       {
+               const tcu::UVec4 threshold (1, 1, 1, 1);
+
+               if (!(tcu::intThresholdCompare(log, "Image comparison", "Image comparison", refRenderbuffer, renderbuffer.getAccess(), threshold, tcu::COMPARE_LOG_ON_ERROR)))
+                       results.fail("Image comparison failed.");
+               else
+                       log << TestLog::Message << "Image comarison passed." << TestLog::EndMessage;
+       }
+       else
+       {
+               const Vec4 threshold = calculateThreshold(format, readPixelsFormat);
+
+               if (!(tcu::floatThresholdCompare(log, "Image comparison", "Image comparison", refRenderbuffer, renderbuffer.getAccess(), threshold, tcu::COMPARE_LOG_ON_ERROR)))
+                       results.fail("Image comparison failed.");
+               else
+                       log << TestLog::Message << "Image comarison passed." << TestLog::EndMessage;
+       }
+}
+
+void verify (tcu::TestContext&                                         testContext,
+                        glu::RenderContext&                                    renderContext,
+                        TextureRenderer&                                               textureRenderer,
+                        tcu::ResultCollector&                                  results,
+                        de::Random&                                                    rng,
+                        deUint32                                                               name,
+                        const vector<ArrayBuffer<deUint8> >&   data,
+                        const ImageInfo&                                               info)
+{
+       switch (info.getTarget())
+       {
+               case GL_TEXTURE_2D:
+                       verifyTexture2D(testContext, renderContext, textureRenderer, results, rng, name, data, info);
+                       break;
+
+               case GL_TEXTURE_3D:
+                       verifyTexture3D(testContext, renderContext, textureRenderer, results, rng, name, data, info);
+                       break;
+
+               case GL_TEXTURE_CUBE_MAP:
+                       verifyTextureCubemap(testContext, renderContext, textureRenderer, results, rng, name, data, info);
+                       break;
+
+               case GL_TEXTURE_2D_ARRAY:
+                       verifyTexture2DArray(testContext, renderContext, textureRenderer, results, rng, name, data, info);
+                       break;
+
+               case GL_RENDERBUFFER:
+                       verifyRenderbuffer(testContext, renderContext, results, name, data, info);
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+}
+
+void logTestImageInfo (TestLog&                        log,
+                                          const ImageInfo&     imageInfo)
+{
+       log << TestLog::Message << "Target: " << targetToName(imageInfo.getTarget()) << TestLog::EndMessage;
+       log << TestLog::Message << "Size: " << imageInfo.getSize() << TestLog::EndMessage;
+       log << TestLog::Message << "Levels: " << getLevelCount(imageInfo) << TestLog::EndMessage;
+       log << TestLog::Message << "Format: " << formatToName(imageInfo.getFormat()) << TestLog::EndMessage;
+}
+
+void logTestInfo (TestLog&                     log,
+                                 const ImageInfo&      srcImageInfo,
+                                 const ImageInfo&      dstImageInfo)
+{
+       tcu::ScopedLogSection section(log, "TestCaseInfo", "Test case info");
+
+       log << TestLog::Message << "Testing copying from " << targetToName(srcImageInfo.getTarget()) << " to " << targetToName(dstImageInfo.getTarget()) << "." << TestLog::EndMessage;
+
+       {
+               tcu::ScopedLogSection srcSection(log, "Source image info.", "Source image info.");
+               logTestImageInfo(log, srcImageInfo);
+       }
+
+       {
+               tcu::ScopedLogSection dstSection(log, "Destination image info.", "Destination image info.");
+               logTestImageInfo(log, dstImageInfo);
+       }
+}
+
+class CopyImageTest : public TestCase
+{
+public:
+                                                       CopyImageTest                   (Context&                       context,
+                                                                                                        const ImageInfo&       srcImage,
+                                                                                                        const ImageInfo&       dstImage,
+                                                                                                        const char*            name,
+                                                                                                        const char*            description);
+
+                                                       ~CopyImageTest                  (void);
+
+       void                                    init                                    (void);
+       void                                    deinit                                  (void);
+
+       TestCase::IterateResult iterate                                 (void);
+
+private:
+       void                                    logTestInfoIter                 (void);
+       void                                    createImagesIter                (void);
+       void                                    destroyImagesIter               (void);
+       void                                    verifySourceIter                (void);
+       void                                    verifyDestinationIter   (void);
+       void                                    copyImageIter                   (void);
+
+       struct State
+       {
+               State (int                                      seed,
+                          tcu::TestContext&    testContext,
+                          glu::RenderContext&  renderContext)
+                       : rng                           (seed)
+                       , results                       (testContext.getLog())
+                       , srcImage                      (NULL)
+                       , dstImage                      (NULL)
+                       , textureRenderer       (renderContext, testContext, glu::GLSL_VERSION_310_ES, glu::PRECISION_HIGHP)
+               {
+               }
+
+               ~State (void)
+               {
+                       delete srcImage;
+                       delete dstImage;
+               }
+
+               de::Random                                              rng;
+               tcu::ResultCollector                    results;
+               glu::ObjectWrapper*                             srcImage;
+               glu::ObjectWrapper*                             dstImage;
+               TextureRenderer                                 textureRenderer;
+
+               vector<ArrayBuffer<deUint8> >   srcImageLevels;
+               vector<ArrayBuffer<deUint8> >   dstImageLevels;
+       };
+
+       const ImageInfo m_srcImageInfo;
+       const ImageInfo m_dstImageInfo;
+
+       int                             m_iteration;
+       State*                  m_state;
+};
+
+CopyImageTest::CopyImageTest (Context&                 context,
+                                                         const ImageInfo&      srcImage,
+                                                         const ImageInfo&      dstImage,
+                                                         const char*           name,
+                                                         const char*           description)
+       : TestCase                      (context, name, description)
+       , m_srcImageInfo        (srcImage)
+       , m_dstImageInfo        (dstImage)
+
+       , m_iteration           (0)
+       , m_state                       (NULL)
+{
+}
+
+CopyImageTest::~CopyImageTest (void)
+{
+       deinit();
+}
+
+void checkFormatSupport (glu::ContextInfo& info, deUint32 format)
+{
+       if (isCompressedFormat(format))
+       {
+               if (isAstcFormat(glu::mapGLCompressedTexFormat(format)))
+               {
+                       if (!info.isExtensionSupported("GL_KHR_texture_compression_astc_ldr")
+                               && !info.isExtensionSupported("GL_KHR_texture_compression_astc_hdr")
+                               && !info.isExtensionSupported("GL_OES_texture_compression_astc"))
+                               throw tcu::NotSupportedError("Compressed astc texture not supported.", "", __FILE__, __LINE__);
+               }
+               else
+               {
+                       if (!info.isCompressedTextureFormatSupported(format))
+                               throw tcu::NotSupportedError("Compressed texture not supported.", "", __FILE__, __LINE__);
+               }
+       }
+}
+
+void CopyImageTest::init (void)
+{
+       de::UniquePtr<glu::ContextInfo> ctxInfo(glu::ContextInfo::create(m_context.getRenderContext()));
+
+       if (!ctxInfo->isExtensionSupported("GL_EXT_copy_image"))
+               throw tcu::NotSupportedError("Extension GL_EXT_copy_image not supported.", "", __FILE__, __LINE__);
+
+       checkFormatSupport(*ctxInfo, m_srcImageInfo.getFormat());
+       checkFormatSupport(*ctxInfo, m_dstImageInfo.getFormat());
+
+       {
+               SeedBuilder builder;
+
+               builder << 903980
+                               << m_srcImageInfo
+                               << m_dstImageInfo;
+
+               m_state = new State(builder.get(), m_testCtx, m_context.getRenderContext());
+       }
+}
+
+void CopyImageTest::deinit (void)
+{
+       delete m_state;
+       m_state = NULL;
+}
+
+void CopyImageTest::logTestInfoIter (void)
+{
+       TestLog& log = m_testCtx.getLog();
+
+       logTestInfo(log, m_srcImageInfo, m_dstImageInfo);
+}
+
+void CopyImageTest::createImagesIter (void)
+{
+       TestLog&                                log                                             = m_testCtx.getLog();
+       glu::RenderContext&             renderContext                   = m_context.getRenderContext();
+       const glw::Functions&   gl                                              = renderContext.getFunctions();
+       const deUint32                  moreRestrictiveFormat   = getMoreRestrictiveFormat(m_srcImageInfo.getFormat(), m_dstImageInfo.getFormat());
+       de::Random&                             rng                                             = m_state->rng;
+
+       DE_ASSERT(!m_state->srcImage);
+       DE_ASSERT(!m_state->dstImage);
+
+       m_state->srcImage = new glu::ObjectWrapper(gl, getObjectTraits(m_srcImageInfo));
+       m_state->dstImage = new glu::ObjectWrapper(gl, getObjectTraits(m_dstImageInfo));
+
+       {
+               glu::ObjectWrapper&                             srcImage                                = *m_state->srcImage;
+               glu::ObjectWrapper&                             dstImage                                = *m_state->dstImage;
+
+               vector<ArrayBuffer<deUint8> >&  srcImageLevels                  = m_state->srcImageLevels;
+               vector<ArrayBuffer<deUint8> >&  dstImageLevels                  = m_state->dstImageLevels;
+
+               log << TestLog::Message << "Creating source image." << TestLog::EndMessage;
+               genImage(gl, rng, *srcImage, srcImageLevels, m_srcImageInfo, moreRestrictiveFormat);
+
+               log << TestLog::Message << "Creating destination image." << TestLog::EndMessage;
+               genImage(gl, rng, *dstImage, dstImageLevels, m_dstImageInfo, moreRestrictiveFormat);
+       }
+}
+
+void CopyImageTest::destroyImagesIter (void)
+{
+       TestLog& log = m_testCtx.getLog();
+
+       log << TestLog::Message << "Deleting source image. " << TestLog::EndMessage;
+
+       delete m_state->srcImage;
+       m_state->srcImage = NULL;
+       m_state->srcImageLevels.clear();
+
+       log << TestLog::Message << "Deleting destination image. " << TestLog::EndMessage;
+
+       delete m_state->dstImage;
+       m_state->dstImage = NULL;
+       m_state->dstImageLevels.clear();
+}
+
+void CopyImageTest::verifySourceIter (void)
+{
+       TestLog&                                                log                                     = m_testCtx.getLog();
+       const tcu::ScopedLogSection             sourceSection           (log, "Source image verify.", "Source image verify.");
+
+       de::Random&                                             rng                                     = m_state->rng;
+       tcu::ResultCollector&                   results                         = m_state->results;
+       glu::ObjectWrapper&                             srcImage                        = *m_state->srcImage;
+       vector<ArrayBuffer<deUint8> >&  srcImageLevels          = m_state->srcImageLevels;
+
+       log << TestLog::Message << "Verifying source image." << TestLog::EndMessage;
+
+       verify(m_testCtx, m_context.getRenderContext(), m_state->textureRenderer, results, rng, *srcImage, srcImageLevels, m_srcImageInfo);
+}
+
+void CopyImageTest::verifyDestinationIter (void)
+{
+       TestLog&                                                log                                     = m_testCtx.getLog();
+       const tcu::ScopedLogSection             destinationSection      (log, "Destination image verify.", "Destination image verify.");
+
+       de::Random&                                             rng                                     = m_state->rng;
+       tcu::ResultCollector&                   results                         = m_state->results;
+       glu::ObjectWrapper&                             dstImage                        = *m_state->dstImage;
+       vector<ArrayBuffer<deUint8> >&  dstImageLevels          = m_state->dstImageLevels;
+
+       log << TestLog::Message << "Verifying destination image." << TestLog::EndMessage;
+
+       verify(m_testCtx, m_context.getRenderContext(), m_state->textureRenderer, results, rng, *dstImage, dstImageLevels, m_dstImageInfo);
+}
+
+struct Copy
+{
+       Copy (const IVec3&      srcPos_,
+                 int                   srcLevel_,
+
+                 const IVec3&  dstPos_,
+                 int                   dstLevel_,
+
+                 const IVec3&  size_)
+               : srcPos        (srcPos_)
+               , srcLevel      (srcLevel_)
+
+               , dstPos        (dstPos_)
+               , dstLevel      (dstLevel_)
+               , size          (size_)
+       {
+       }
+
+       IVec3   srcPos;
+       int             srcLevel;
+       IVec3   dstPos;
+       int             dstLevel;
+       IVec3   size;
+};
+
+int getLastFullLevel (const ImageInfo& info)
+{
+       const int       levelCount              = getLevelCount(info);
+       const IVec3     blockPixelSize  = getTexelBlockPixelSize(info.getFormat());
+
+       for (int level = 0; level < levelCount; level++)
+       {
+               const IVec3 levelSize = getLevelSize(info.getTarget(), info.getSize(), level);
+
+               if (levelSize.x() < blockPixelSize.x() || levelSize.y() < blockPixelSize.y() || levelSize.z() < blockPixelSize.z())
+                       return level - 1;
+       }
+
+       return levelCount -1;
+}
+
+void generateCopies (vector<Copy>& copies, const ImageInfo& srcInfo, const ImageInfo& dstInfo)
+{
+       const deUint32  srcTarget               = srcInfo.getTarget();
+       const deUint32  dstTarget               = dstInfo.getTarget();
+
+       const bool              srcIsTexture    = isTextureTarget(srcInfo.getTarget());
+       const bool              dstIsTexture    = isTextureTarget(dstInfo.getTarget());
+
+       const bool              srcIsCube               = srcTarget == GL_TEXTURE_CUBE_MAP;
+       const bool              dstIsCube               = dstTarget == GL_TEXTURE_CUBE_MAP;
+
+       const IVec3             srcBlockPixelSize               = getTexelBlockPixelSize(srcInfo.getFormat());
+       const IVec3             dstBlockPixelSize               = getTexelBlockPixelSize(dstInfo.getFormat());
+
+       const int levels[] =
+       {
+               0, 1, -1
+       };
+
+       for (int levelNdx = 0; levelNdx < (srcIsTexture || dstIsTexture ? DE_LENGTH_OF_ARRAY(levels) : 1); levelNdx++)
+       {
+               const int       srcLevel                                = (srcIsTexture ? (levels[levelNdx] >= 0 ? levels[levelNdx] : getLastFullLevel(srcInfo)) : 0);
+               const int       dstLevel                                = (dstIsTexture ? (levels[levelNdx] >= 0 ? levels[levelNdx] : getLastFullLevel(dstInfo)) : 0);
+
+               const IVec3     srcSize                                 = getLevelSize(srcInfo.getTarget(), srcInfo.getSize(), srcLevel);
+               const IVec3     dstSize                                 = getLevelSize(dstInfo.getTarget(), dstInfo.getSize(), dstLevel);
+
+               // \note These are rounded down
+               const IVec3     srcCompleteBlockSize    = IVec3(srcSize.x() / srcBlockPixelSize.x(), srcSize.y() / srcBlockPixelSize.y(), (srcIsCube ? 6 : srcSize.z() / srcBlockPixelSize.z()));
+               const IVec3     dstCompleteBlockSize    = IVec3(dstSize.x() / dstBlockPixelSize.x(), dstSize.y() / dstBlockPixelSize.y(), (dstIsCube ? 6 : dstSize.z() / dstBlockPixelSize.z()));
+
+               const IVec3     maxCopyBlockSize                = tcu::min(srcCompleteBlockSize, dstCompleteBlockSize);
+
+               // \note These are rounded down
+               const int       copyBlockWidth                  = de::max((2 * (maxCopyBlockSize.x() / 4)) - 1, 1);
+               const int       copyBlockHeight                 = de::max((2 * (maxCopyBlockSize.y() / 4)) - 1, 1);
+               const int       copyBlockDepth                  = de::max((2 * (maxCopyBlockSize.z() / 4)) - 1, 1);
+
+               // Copy NPOT block from (0,0,0) to other corner on dst
+               {
+                       const IVec3     copyBlockSize   (copyBlockWidth, copyBlockHeight, copyBlockDepth);
+                       const IVec3     srcBlockPos             (srcCompleteBlockSize - copyBlockSize);
+                       const IVec3     dstBlockPos             (0, 0, 0);
+
+                       const IVec3     srcPos                  (srcBlockPos * srcBlockPixelSize);
+                       const IVec3     dstPos                  (dstBlockPos * dstBlockPixelSize);
+                       const IVec3 copySize            (copyBlockSize * srcBlockPixelSize);
+
+                       copies.push_back(Copy(srcPos, srcLevel, dstPos, dstLevel, copySize));
+               }
+
+               // Copy NPOT block to (0,0,0) from other corner on src
+               {
+                       const IVec3     copyBlockSize   (copyBlockWidth, copyBlockHeight, copyBlockDepth);
+                       const IVec3     srcBlockPos             (0, 0, 0);
+                       const IVec3     dstBlockPos             (dstCompleteBlockSize - copyBlockSize);
+
+                       const IVec3     srcPos                  (srcBlockPos * srcBlockPixelSize);
+                       const IVec3     dstPos                  (dstBlockPos * dstBlockPixelSize);
+                       const IVec3 copySize            (copyBlockSize * srcBlockPixelSize);
+
+                       copies.push_back(Copy(srcPos, srcLevel, dstPos, dstLevel, copySize));
+               }
+
+               // Copy NPOT block to (0,0,0) from other corner on src
+               {
+                       const IVec3     copyBlockSize   (copyBlockWidth, copyBlockHeight, copyBlockDepth);
+                       const IVec3     srcBlockPos             (tcu::max((srcCompleteBlockSize / 4) * 4 - copyBlockSize, IVec3(0)));
+                       const IVec3     dstBlockPos             (tcu::max((dstCompleteBlockSize / 4) * 4 - copyBlockSize, IVec3(0)));
+
+                       const IVec3     srcPos                  (srcBlockPos * srcBlockPixelSize);
+                       const IVec3     dstPos                  (dstBlockPos * dstBlockPixelSize);
+                       const IVec3 copySize            (copyBlockSize * srcBlockPixelSize);
+
+                       copies.push_back(Copy(srcPos, srcLevel, dstPos, dstLevel, copySize));
+               }
+       }
+}
+
+void CopyImageTest::copyImageIter (void)
+{
+       TestLog&                                                log                             = m_testCtx.getLog();
+       const glw::Functions&                   gl                              = m_context.getRenderContext().getFunctions();
+       glu::ObjectWrapper&                             srcImage                = *m_state->srcImage;
+       glu::ObjectWrapper&                             dstImage                = *m_state->dstImage;
+
+       vector<ArrayBuffer<deUint8> >&  srcImageLevels  = m_state->srcImageLevels;
+       vector<ArrayBuffer<deUint8> >&  dstImageLevels  = m_state->dstImageLevels;
+       vector<Copy>                                    copies;
+
+       generateCopies(copies, m_srcImageInfo, m_dstImageInfo);
+
+       for (int copyNdx = 0; copyNdx < (int)copies.size(); copyNdx++)
+       {
+               const Copy& copy = copies[copyNdx];
+
+               log << TestLog::Message << "Copying block " << copy.size << " from source image position " << copy.srcPos << " and mipmap level " << copy.srcLevel
+                                                               << " to destination image position " << copy.dstPos << " and mipmap level " << copy.dstLevel << TestLog::EndMessage;
+
+               copyImage(gl, *dstImage, dstImageLevels, m_dstImageInfo, copy.dstLevel, copy.dstPos,
+                                         *srcImage, srcImageLevels, m_srcImageInfo, copy.srcLevel, copy.srcPos, copy.size);
+       }
+}
+
+TestCase::IterateResult CopyImageTest::iterate (void)
+{
+       void(CopyImageTest::*methods[])(void) =
+       {
+               &CopyImageTest::logTestInfoIter,
+
+               // Render both images and then copy and verify again.
+               &CopyImageTest::createImagesIter,
+               &CopyImageTest::verifySourceIter,
+               &CopyImageTest::verifyDestinationIter,
+               &CopyImageTest::copyImageIter,
+               &CopyImageTest::verifySourceIter,
+               &CopyImageTest::verifyDestinationIter,
+               &CopyImageTest::destroyImagesIter,
+
+               // Create images and immediately copies between thew and verify.
+               &CopyImageTest::createImagesIter,
+               &CopyImageTest::copyImageIter,
+               &CopyImageTest::verifySourceIter,
+               &CopyImageTest::verifyDestinationIter,
+               &CopyImageTest::destroyImagesIter
+       };
+
+       if (m_iteration < DE_LENGTH_OF_ARRAY(methods))
+       {
+               (this->*methods[m_iteration])();
+               m_iteration++;
+               return CONTINUE;
+       }
+       else
+       {
+               m_state->results.setTestContextResult(m_testCtx);
+               return STOP;
+       }
+}
+
+class CopyImageTests : public TestCaseGroup
+{
+public:
+                                               CopyImageTests                  (Context& context);
+                                               ~CopyImageTests                 (void);
+
+       void                            init                                    (void);
+
+private:
+                                               CopyImageTests                  (const CopyImageTests& other);
+       CopyImageTests&         operator=                               (const CopyImageTests& other);
+};
+
+CopyImageTests::CopyImageTests (Context& context)
+       : TestCaseGroup (context, "copy_image", "Copy image tests for GL_EXT_copy_image.")
+{
+}
+
+CopyImageTests::~CopyImageTests (void)
+{
+}
+
+int smallestCommonMultiple (int a_, int b_)
+{
+       int     a               = (a_ > b_ ? a_ : b_);
+       int     b               = (a_ > b_ ? b_ : a_);
+       int     result  = 1;
+
+       for (int i = b/2; i > 1; i--)
+       {
+               while ((a % i) == 0 && (b % i) == 0)
+               {
+                       result *= i;
+                       a /= i;
+                       b /= i;
+               }
+       }
+
+       return result * a * b;
+}
+
+IVec3 getTestedSize (deUint32 target, deUint32 format, const IVec3& targetSize)
+{
+       const IVec3 texelBlockPixelSize = getTexelBlockPixelSize(format);
+       const bool      isCube                          = target == GL_TEXTURE_CUBE_MAP;
+       const bool      is3D                            = target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY;
+
+       if (isCube)
+       {
+               const int       multiplier      = smallestCommonMultiple(texelBlockPixelSize.x(), texelBlockPixelSize.y());
+               const int       size            = (1 + (targetSize.x() / multiplier)) * multiplier;
+
+               return IVec3(size, size, 1);
+       }
+       else if (is3D)
+       {
+               return (1 + (targetSize / texelBlockPixelSize)) * texelBlockPixelSize;
+       }
+       else
+       {
+               const int width = (1 + targetSize.x() / texelBlockPixelSize.x()) * texelBlockPixelSize.x();
+               const int height = ((targetSize.y() / texelBlockPixelSize.y()) - 1) * texelBlockPixelSize.y();
+
+               return IVec3(width, height, 1);
+       }
+}
+
+void addCopyTests (TestCaseGroup* root, deUint32 srcFormat, deUint32 dstFormat)
+{
+       const string                    groupName       = string(formatToName(srcFormat)) + "_" + formatToName(dstFormat);
+       TestCaseGroup* const    group           = new TestCaseGroup(root->getContext(), groupName.c_str(), groupName.c_str());
+
+       const deUint32 targets[] =
+       {
+               GL_TEXTURE_2D,
+               GL_TEXTURE_3D,
+               GL_TEXTURE_CUBE_MAP,
+               GL_TEXTURE_2D_ARRAY,
+               GL_RENDERBUFFER
+       };
+
+       root->addChild(group);
+
+       for (int srcTargetNdx = 0; srcTargetNdx < DE_LENGTH_OF_ARRAY(targets); srcTargetNdx++)
+       {
+               const deUint32  srcTarget                               = targets[srcTargetNdx];
+               const IVec3             srcTexelBlockPixelSize  = getTexelBlockPixelSize(srcFormat);
+               const bool              srcIs3D                                 = srcTarget == GL_TEXTURE_2D_ARRAY || srcTarget == GL_TEXTURE_3D;
+
+               if (isCompressedFormat(srcFormat) && srcTarget == GL_RENDERBUFFER)
+                       continue;
+
+               if (srcTarget == GL_RENDERBUFFER && !isColorRenderable(srcFormat))
+                       continue;
+
+               if (isCompressedFormat(srcFormat) && !tcu::isAstcFormat(glu::mapGLCompressedTexFormat(srcFormat)) && srcIs3D)
+                       continue;
+
+               for (int dstTargetNdx = 0; dstTargetNdx < DE_LENGTH_OF_ARRAY(targets); dstTargetNdx++)
+               {
+                       const deUint32  dstTarget                               = targets[dstTargetNdx];
+                       const IVec3             dstTexelBlockPixelSize  = getTexelBlockPixelSize(dstFormat);
+                       const bool              dstIs3D                                 = dstTarget == GL_TEXTURE_2D_ARRAY || dstTarget == GL_TEXTURE_3D;
+
+                       if (isCompressedFormat(dstFormat) && dstTarget == GL_RENDERBUFFER)
+                               continue;
+
+                       if (dstTarget == GL_RENDERBUFFER && !isColorRenderable(dstFormat))
+                               continue;
+
+                       if (isCompressedFormat(dstFormat) && !tcu::isAstcFormat(glu::mapGLCompressedTexFormat(dstFormat)) && dstIs3D)
+                               continue;
+
+                       const string    targetTestName  = string(targetToName(srcTarget)) + "_to_" + targetToName(dstTarget);
+
+                       const IVec3             targetSize2D    (128, 128, 1);
+                       const IVec3             targetSize3D    (128, 128, 16);
+
+                       const IVec3             targetPos2D             (32, 32, 0);
+                       const IVec3             targetPos3D             (16, 16, 2);
+                       const IVec3             targetCopySize  (16, 16, 4);
+
+                       const IVec3             srcSize                 = getTestedSize(srcTarget, srcFormat, (srcIs3D ? targetSize3D : targetSize2D));
+                       const IVec3             dstSize                 = getTestedSize(dstTarget, dstFormat, (dstIs3D ? targetSize3D : targetSize2D));
+
+                       group->addChild(new CopyImageTest(root->getContext(),
+                                                                                       ImageInfo(srcFormat, srcTarget, srcSize),
+                                                                                       ImageInfo(dstFormat, dstTarget, dstSize),
+                                                                                       targetTestName.c_str(), targetTestName.c_str()));
+               }
+       }
+}
+
+void CopyImageTests::init (void)
+{
+       TestCaseGroup* const    nonCompressedGroup      = new TestCaseGroup(m_context, "non_compressed", "Test copying between textures.");
+       TestCaseGroup* const    compressedGroup         = new TestCaseGroup(m_context, "compressed", "Test copying between compressed textures.");
+       TestCaseGroup* const    mixedGroup                      = new TestCaseGroup(m_context, "mixed", "Test copying between compressed and non-compressed textures.");
+
+       addChild(nonCompressedGroup);
+       addChild(compressedGroup);
+       addChild(mixedGroup);
+
+       map<ViewClass, vector<deUint32> >                                                       textureFormatViewClasses;
+       map<ViewClass, vector<deUint32> >                                                       compressedTextureFormatViewClasses;
+       map<ViewClass, pair<vector<deUint32>, vector<deUint32> > >      mixedViewClasses;
+
+       // Texture view classes
+       textureFormatViewClasses[VIEWCLASS_128_BITS]            = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_96_BITS]                     = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_64_BITS]                     = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_48_BITS]                     = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_32_BITS]                     = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_24_BITS]                     = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_16_BITS]                     = vector<deUint32>();
+       textureFormatViewClasses[VIEWCLASS_8_BITS]                      = vector<deUint32>();
+
+       // 128bit / VIEWCLASS_128_BITS
+       textureFormatViewClasses[VIEWCLASS_128_BITS].push_back(GL_RGBA32F);
+       textureFormatViewClasses[VIEWCLASS_128_BITS].push_back(GL_RGBA32I);
+       textureFormatViewClasses[VIEWCLASS_128_BITS].push_back(GL_RGBA32UI);
+
+       // 96bit / VIEWCLASS_96_BITS
+       textureFormatViewClasses[VIEWCLASS_96_BITS].push_back(GL_RGB32F);
+       textureFormatViewClasses[VIEWCLASS_96_BITS].push_back(GL_RGB32I);
+       textureFormatViewClasses[VIEWCLASS_96_BITS].push_back(GL_RGB32UI);
+
+       // 64bit / VIEWCLASS_64_BITS
+       textureFormatViewClasses[VIEWCLASS_64_BITS].push_back(GL_RG32F);
+       textureFormatViewClasses[VIEWCLASS_64_BITS].push_back(GL_RG32I);
+       textureFormatViewClasses[VIEWCLASS_64_BITS].push_back(GL_RG32UI);
+
+       textureFormatViewClasses[VIEWCLASS_64_BITS].push_back(GL_RGBA16F);
+       textureFormatViewClasses[VIEWCLASS_64_BITS].push_back(GL_RGBA16I);
+       textureFormatViewClasses[VIEWCLASS_64_BITS].push_back(GL_RGBA16UI);
+
+       // 48bit / VIEWCLASS_48_BITS
+       textureFormatViewClasses[VIEWCLASS_48_BITS].push_back(GL_RGB16F);
+       textureFormatViewClasses[VIEWCLASS_48_BITS].push_back(GL_RGB16I);
+       textureFormatViewClasses[VIEWCLASS_48_BITS].push_back(GL_RGB16UI);
+
+       // 32bit / VIEWCLASS_32_BITS
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_R32F);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_R32I);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_R32UI);
+
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RG16F);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RG16I);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RG16UI);
+
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGBA8);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGBA8I);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGBA8UI);
+
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_R11F_G11F_B10F);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGB10_A2UI);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGB10_A2);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGBA8_SNORM);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_SRGB8_ALPHA8);
+       textureFormatViewClasses[VIEWCLASS_32_BITS].push_back(GL_RGB9_E5);
+
+       // 24bit / VIEWCLASS_24_BITS
+       textureFormatViewClasses[VIEWCLASS_24_BITS].push_back(GL_RGB8);
+       textureFormatViewClasses[VIEWCLASS_24_BITS].push_back(GL_RGB8I);
+       textureFormatViewClasses[VIEWCLASS_24_BITS].push_back(GL_RGB8UI);
+       textureFormatViewClasses[VIEWCLASS_24_BITS].push_back(GL_RGB8_SNORM);
+       textureFormatViewClasses[VIEWCLASS_24_BITS].push_back(GL_SRGB8);
+
+       // 16bit / VIEWCLASS_16_BITS
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_R16F);
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_R16I);
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_R16UI);
+
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_RG8);
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_RG8I);
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_RG8UI);
+       textureFormatViewClasses[VIEWCLASS_16_BITS].push_back(GL_RG8_SNORM);
+
+       // 8bit / VIEWCLASS_8_BITS
+       textureFormatViewClasses[VIEWCLASS_8_BITS].push_back(GL_R8);
+       textureFormatViewClasses[VIEWCLASS_8_BITS].push_back(GL_R8I);
+       textureFormatViewClasses[VIEWCLASS_8_BITS].push_back(GL_R8UI);
+       textureFormatViewClasses[VIEWCLASS_8_BITS].push_back(GL_R8_SNORM);
+
+       // Compressed texture view classes
+       compressedTextureFormatViewClasses[VIEWCLASS_EAC_R11]                   = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_EAC_RG11]                  = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_RGB]                  = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_RGBA]                 = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_EAC_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_4x4_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_5x4_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_5x5_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_6x5_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_6x6_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x5_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x6_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x8_RGBA]             = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x5_RGBA]    = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x6_RGBA]    = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x8_RGBA]    = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x10_RGBA]   = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_12x10_RGBA]   = vector<deUint32>();
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_12x12_RGBA]   = vector<deUint32>();
+
+       // VIEWCLASS_EAC_R11
+       compressedTextureFormatViewClasses[VIEWCLASS_EAC_R11].push_back(GL_COMPRESSED_R11_EAC);
+       compressedTextureFormatViewClasses[VIEWCLASS_EAC_R11].push_back(GL_COMPRESSED_SIGNED_R11_EAC);
+
+       // VIEWCLASS_EAC_RG11
+       compressedTextureFormatViewClasses[VIEWCLASS_EAC_RG11].push_back(GL_COMPRESSED_RG11_EAC);
+       compressedTextureFormatViewClasses[VIEWCLASS_EAC_RG11].push_back(GL_COMPRESSED_SIGNED_RG11_EAC);
+
+       // VIEWCLASS_ETC2_RGB
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_RGB].push_back(GL_COMPRESSED_RGB8_ETC2);
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_RGB].push_back(GL_COMPRESSED_SRGB8_ETC2);
+
+       // VIEWCLASS_ETC2_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_RGBA].push_back(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2);
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_RGBA].push_back(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2);
+
+       // VIEWCLASS_ETC2_EAC_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_EAC_RGBA].push_back(GL_COMPRESSED_RGBA8_ETC2_EAC);
+       compressedTextureFormatViewClasses[VIEWCLASS_ETC2_EAC_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC);
+
+       // VIEWCLASS_ASTC_4x4_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_4x4_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_4x4_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
+
+       // VIEWCLASS_ASTC_5x4_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_5x4_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_5x4_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR);
+
+       // VIEWCLASS_ASTC_5x5_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_5x5_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_5x5_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR);
+
+       // VIEWCLASS_ASTC_6x5_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_6x5_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_6x5_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR);
+
+       // VIEWCLASS_ASTC_6x6_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_6x6_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_6x6_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR);
+
+       // VIEWCLASS_ASTC_8x5_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x5_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x5_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR);
+
+       // VIEWCLASS_ASTC_8x6_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x6_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x6_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR);
+
+       // VIEWCLASS_ASTC_8x8_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x8_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_8x8_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR);
+
+       // VIEWCLASS_ASTC_10x5_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x5_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x5_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR);
+
+       // VIEWCLASS_ASTC_10x6_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x6_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x6_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR);
+
+       // VIEWCLASS_ASTC_10x8_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x8_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x8_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR);
+
+       // VIEWCLASS_ASTC_10x10_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x10_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_10x10_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR);
+
+       // VIEWCLASS_ASTC_12x10_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_12x10_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_12x10_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR);
+
+       // VIEWCLASS_ASTC_12x12_RGBA
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_12x12_RGBA].push_back(GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
+       compressedTextureFormatViewClasses[VIEWCLASS_ASTC_12x12_RGBA].push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
+
+       // Mixed view classes
+       mixedViewClasses[VIEWCLASS_128_BITS] = pair<vector<deUint32>, vector<deUint32> >();
+       mixedViewClasses[VIEWCLASS_64_BITS] = pair<vector<deUint32>, vector<deUint32> >();
+
+       // 128 bits
+
+       // Non compressed
+       mixedViewClasses[VIEWCLASS_128_BITS].first.push_back(GL_RGBA32F);
+       mixedViewClasses[VIEWCLASS_128_BITS].first.push_back(GL_RGBA32UI);
+       mixedViewClasses[VIEWCLASS_128_BITS].first.push_back(GL_RGBA32I);
+
+       // Compressed
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA8_ETC2_EAC);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RG11_EAC);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SIGNED_RG11_EAC);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR);
+       mixedViewClasses[VIEWCLASS_128_BITS].second.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
+
+       // 64 bits
+
+       // Non compressed
+       mixedViewClasses[VIEWCLASS_64_BITS].first.push_back(GL_RGBA16F);
+       mixedViewClasses[VIEWCLASS_64_BITS].first.push_back(GL_RGBA16UI);
+       mixedViewClasses[VIEWCLASS_64_BITS].first.push_back(GL_RGBA16I);
+
+       mixedViewClasses[VIEWCLASS_64_BITS].first.push_back(GL_RG32F);
+       mixedViewClasses[VIEWCLASS_64_BITS].first.push_back(GL_RG32UI);
+       mixedViewClasses[VIEWCLASS_64_BITS].first.push_back(GL_RG32I);
+
+       // Compressed
+       mixedViewClasses[VIEWCLASS_64_BITS].second.push_back(GL_COMPRESSED_R11_EAC);
+       mixedViewClasses[VIEWCLASS_64_BITS].second.push_back(GL_COMPRESSED_SIGNED_R11_EAC);
+
+       for (map<ViewClass, vector<deUint32> >::const_iterator viewClassIter = textureFormatViewClasses.begin(); viewClassIter != textureFormatViewClasses.end(); ++viewClassIter)
+       {
+               const vector<deUint32>& formats         = viewClassIter->second;
+               const ViewClass                 viewClass       = viewClassIter->first;
+               TestCaseGroup* const    viewGroup       = new TestCaseGroup(m_context, viewClassToName(viewClass), viewClassToName(viewClass));
+
+               nonCompressedGroup->addChild(viewGroup);
+
+               for (int srcFormatNdx = 0; srcFormatNdx < (int)formats.size(); srcFormatNdx++)
+               for (int dstFormatNdx = 0; dstFormatNdx < (int)formats.size(); dstFormatNdx++)
+               {
+                       const deUint32 srcFormat = formats[srcFormatNdx];
+                       const deUint32 dstFormat = formats[dstFormatNdx];
+
+                       if (srcFormat != dstFormat && isFloatFormat(srcFormat) && isFloatFormat(dstFormat))
+                               continue;
+
+                       addCopyTests(viewGroup, srcFormat, dstFormat);
+               }
+       }
+
+       for (map<ViewClass, vector<deUint32> >::const_iterator viewClassIter = compressedTextureFormatViewClasses.begin(); viewClassIter != compressedTextureFormatViewClasses.end(); ++viewClassIter)
+       {
+               const vector<deUint32>& formats         = viewClassIter->second;
+               const ViewClass                 viewClass       = viewClassIter->first;
+               TestCaseGroup* const    viewGroup       = new TestCaseGroup(m_context, viewClassToName(viewClass), viewClassToName(viewClass));
+
+               compressedGroup->addChild(viewGroup);
+
+               for (int srcFormatNdx = 0; srcFormatNdx < (int)formats.size(); srcFormatNdx++)
+               for (int dstFormatNdx = 0; dstFormatNdx < (int)formats.size(); dstFormatNdx++)
+               {
+                       const deUint32 srcFormat = formats[srcFormatNdx];
+                       const deUint32 dstFormat = formats[dstFormatNdx];
+
+                       if (srcFormat != dstFormat && isFloatFormat(srcFormat) && isFloatFormat(dstFormat))
+                               continue;
+
+                       addCopyTests(viewGroup, srcFormat, dstFormat);
+               }
+       }
+
+       for (map<ViewClass, pair<vector<deUint32>, vector<deUint32> > >::const_iterator iter = mixedViewClasses.begin(); iter != mixedViewClasses.end(); ++iter)
+       {
+               const ViewClass                 viewClass                               = iter->first;
+               const string                    viewClassName                   = string(viewClassToName(viewClass)) + "_mixed";
+               TestCaseGroup* const    viewGroup                               = new TestCaseGroup(m_context, viewClassName.c_str(), viewClassName.c_str());
+
+               const vector<deUint32>  nonCompressedFormats    = iter->second.first;
+               const vector<deUint32>  compressedFormats               = iter->second.second;
+
+               mixedGroup->addChild(viewGroup);
+
+               for (int srcFormatNdx = 0; srcFormatNdx < (int)nonCompressedFormats.size(); srcFormatNdx++)
+               for (int dstFormatNdx = 0; dstFormatNdx < (int)compressedFormats.size(); dstFormatNdx++)
+               {
+                       const deUint32 srcFormat = nonCompressedFormats[srcFormatNdx];
+                       const deUint32 dstFormat = compressedFormats[dstFormatNdx];
+
+                       if (srcFormat != dstFormat && isFloatFormat(srcFormat) && isFloatFormat(dstFormat))
+                               continue;
+
+                       addCopyTests(viewGroup, srcFormat, dstFormat);
+                       addCopyTests(viewGroup, dstFormat, srcFormat);
+               }
+       }
+}
+
+} // anonymous
+
+TestCaseGroup* createCopyImageTests (Context& context)
+{
+       return new CopyImageTests(context);
+}
+
+} // Functional
+} // gles31
+} // deqp
diff --git a/modules/gles31/functional/es31fCopyImageTests.hpp b/modules/gles31/functional/es31fCopyImageTests.hpp
new file mode 100644 (file)
index 0000000..5a7d929
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _ES31FCOPYIMAGETESTS_HPP
+#define _ES31FCOPYIMAGETESTS_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Copy image tests for GL_EXT_copy_image.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tes31TestCase.hpp"
+
+namespace deqp
+{
+namespace gles31
+{
+class TestCaseGroup;
+class Context;
+
+namespace Functional
+{
+
+TestCaseGroup* createCopyImageTests (Context& context);
+
+} // Functional
+} // gles31
+} // deqp
+
+#endif // _ES31FCOPYIMAGETESTS_HPP
index 214222c..582ea45 100644 (file)
@@ -77,6 +77,7 @@
 #include "es31fShaderHelperInvocationTests.hpp"
 #include "es31fPrimitiveBoundingBoxTests.hpp"
 #include "es31fAndroidExtensionPackES31ATests.hpp"
+#include "es31fCopyImageTests.hpp"
 
 namespace deqp
 {
@@ -312,7 +313,7 @@ void FunctionalTests::init (void)
        addChild(new LayoutBindingTests                                         (m_context));
        addChild(new PrimitiveBoundingBoxTests                          (m_context));
        addChild(new AndroidExtensionPackES31ATests                     (m_context));
-
+       addChild(createCopyImageTests                                           (m_context));
 }
 
 } // Functional