/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES Utilities
 * ------------------------------------------------
 *
 * 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 Texture format utilities.
 *//*--------------------------------------------------------------------*/

#include "gluTextureUtil.hpp"
#include "gluRenderContext.hpp"
#include "gluContextInfo.hpp"
#include "gluTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuFormatUtil.hpp"
#include "glwEnums.hpp"

namespace glu
{

using std::string;

/*--------------------------------------------------------------------*//*!
 * \brief Map tcu::TextureFormat to GL pixel transfer format.
 *
 * Maps generic texture format description to GL pixel transfer format.
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param texFormat Generic texture format.
 * \return GL pixel transfer format.
 *//*--------------------------------------------------------------------*/
TransferFormat getTransferFormat (tcu::TextureFormat texFormat)
{
	using tcu::TextureFormat;

	deUint32	format	= GL_NONE;
	deUint32	type	= GL_NONE;
	bool		isInt	= false;

	switch (texFormat.type)
	{
		case TextureFormat::SIGNED_INT8:
		case TextureFormat::SIGNED_INT16:
		case TextureFormat::SIGNED_INT32:
		case TextureFormat::UNSIGNED_INT8:
		case TextureFormat::UNSIGNED_INT16:
		case TextureFormat::UNSIGNED_INT32:
		case TextureFormat::UNSIGNED_INT_1010102_REV:
			isInt = true;
			break;

		default:
			isInt = false;
			break;
	}

	switch (texFormat.order)
	{
		case TextureFormat::A:		format = GL_ALPHA;								break;
		case TextureFormat::L:		format = GL_LUMINANCE;							break;
		case TextureFormat::LA:		format = GL_LUMINANCE_ALPHA;					break;
		case TextureFormat::R:		format = isInt ? GL_RED_INTEGER		: GL_RED;	break;
		case TextureFormat::RG:		format = isInt ? GL_RG_INTEGER		: GL_RG;	break;
		case TextureFormat::RGB:	format = isInt ? GL_RGB_INTEGER		: GL_RGB;	break;
		case TextureFormat::RGBA:	format = isInt ? GL_RGBA_INTEGER	: GL_RGBA;	break;
		case TextureFormat::sR:		format = GL_RED;								break;
		case TextureFormat::sRG:	format = GL_RG;									break;
		case TextureFormat::sRGB:	format = GL_RGB;								break;
		case TextureFormat::sRGBA:	format = GL_RGBA;								break;
		case TextureFormat::D:		format = GL_DEPTH_COMPONENT;					break;
		case TextureFormat::DS:		format = GL_DEPTH_STENCIL;						break;
		case TextureFormat::S:		format = GL_STENCIL_INDEX;						break;

		case TextureFormat::BGRA:
			DE_ASSERT(!isInt);
			format = GL_BGRA;
			break;

		default:
			DE_ASSERT(false);
	}

	switch (texFormat.type)
	{
		case TextureFormat::SNORM_INT8:						type = GL_BYTE;								break;
		case TextureFormat::SNORM_INT16:					type = GL_SHORT;							break;
		case TextureFormat::UNORM_INT8:						type = GL_UNSIGNED_BYTE;					break;
		case TextureFormat::UNORM_INT16:					type = GL_UNSIGNED_SHORT;					break;
		case TextureFormat::UNORM_SHORT_565:				type = GL_UNSIGNED_SHORT_5_6_5;				break;
		case TextureFormat::UNORM_SHORT_4444:				type = GL_UNSIGNED_SHORT_4_4_4_4;			break;
		case TextureFormat::UNORM_SHORT_5551:				type = GL_UNSIGNED_SHORT_5_5_5_1;			break;
		case TextureFormat::SIGNED_INT8:					type = GL_BYTE;								break;
		case TextureFormat::SIGNED_INT16:					type = GL_SHORT;							break;
		case TextureFormat::SIGNED_INT32:					type = GL_INT;								break;
		case TextureFormat::UNSIGNED_INT8:					type = GL_UNSIGNED_BYTE;					break;
		case TextureFormat::UNSIGNED_INT16:					type = GL_UNSIGNED_SHORT;					break;
		case TextureFormat::UNSIGNED_INT32:					type = GL_UNSIGNED_INT;						break;
		case TextureFormat::FLOAT:							type = GL_FLOAT;							break;
		case TextureFormat::UNORM_INT_101010:				type = GL_UNSIGNED_INT_2_10_10_10_REV;		break;
		case TextureFormat::UNORM_INT_1010102_REV:			type = GL_UNSIGNED_INT_2_10_10_10_REV;		break;
		case TextureFormat::UNSIGNED_INT_1010102_REV:		type = GL_UNSIGNED_INT_2_10_10_10_REV;		break;
		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	type = GL_UNSIGNED_INT_10F_11F_11F_REV;		break;
		case TextureFormat::UNSIGNED_INT_999_E5_REV:		type = GL_UNSIGNED_INT_5_9_9_9_REV;			break;
		case TextureFormat::HALF_FLOAT:						type = GL_HALF_FLOAT;						break;
		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;	break;
		case TextureFormat::UNSIGNED_INT_24_8:				type = texFormat.order == TextureFormat::D
																 ? GL_UNSIGNED_INT
																 : GL_UNSIGNED_INT_24_8;				break;

		default:
			throw tcu::InternalError("Can't map texture format to GL transfer format");
	}

	return TransferFormat(format, type);
}

/*--------------------------------------------------------------------*//*!
 * \brief Map tcu::TextureFormat to GL internal sized format.
 *
 * Maps generic texture format description to GL internal format.
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param texFormat Generic texture format.
 * \return GL sized internal format.
 *//*--------------------------------------------------------------------*/
deUint32 getInternalFormat (tcu::TextureFormat texFormat)
{
	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST < (1<<16));
	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELTYPE_LAST < (1<<16));

#define PACK_FMT(ORDER, TYPE) ((int(ORDER) << 16) | int(TYPE))
#define FMT_CASE(ORDER, TYPE) PACK_FMT(tcu::TextureFormat::ORDER, tcu::TextureFormat::TYPE)

	switch (PACK_FMT(texFormat.order, texFormat.type))
	{
		case FMT_CASE(RGBA,		UNORM_SHORT_5551):				return GL_RGB5_A1;
		case FMT_CASE(RGBA,		UNORM_SHORT_4444):				return GL_RGBA4;
		case FMT_CASE(RGB,		UNORM_SHORT_565):				return GL_RGB565;
		case FMT_CASE(D,		UNORM_INT16):					return GL_DEPTH_COMPONENT16;
		case FMT_CASE(S,		UNSIGNED_INT8):					return GL_STENCIL_INDEX8;

		case FMT_CASE(RGBA,		FLOAT):							return GL_RGBA32F;
		case FMT_CASE(RGBA,		SIGNED_INT32):					return GL_RGBA32I;
		case FMT_CASE(RGBA,		UNSIGNED_INT32):				return GL_RGBA32UI;
		case FMT_CASE(RGBA,		UNORM_INT16):					return GL_RGBA16;
		case FMT_CASE(RGBA,		SNORM_INT16):					return GL_RGBA16_SNORM;
		case FMT_CASE(RGBA,		HALF_FLOAT):					return GL_RGBA16F;
		case FMT_CASE(RGBA,		SIGNED_INT16):					return GL_RGBA16I;
		case FMT_CASE(RGBA,		UNSIGNED_INT16):				return GL_RGBA16UI;
		case FMT_CASE(RGBA,		UNORM_INT8):					return GL_RGBA8;
		case FMT_CASE(RGBA,		SIGNED_INT8):					return GL_RGBA8I;
		case FMT_CASE(RGBA,		UNSIGNED_INT8):					return GL_RGBA8UI;
		case FMT_CASE(sRGBA,	UNORM_INT8):					return GL_SRGB8_ALPHA8;
		case FMT_CASE(RGBA,		UNORM_INT_1010102_REV):			return GL_RGB10_A2;
		case FMT_CASE(RGBA,		UNSIGNED_INT_1010102_REV):		return GL_RGB10_A2UI;
		case FMT_CASE(RGBA,		SNORM_INT8):					return GL_RGBA8_SNORM;

		case FMT_CASE(RGB,		UNORM_INT8):					return GL_RGB8;
		case FMT_CASE(RGB,		UNSIGNED_INT_11F_11F_10F_REV):	return GL_R11F_G11F_B10F;
		case FMT_CASE(RGB,		FLOAT):							return GL_RGB32F;
		case FMT_CASE(RGB,		SIGNED_INT32):					return GL_RGB32I;
		case FMT_CASE(RGB,		UNSIGNED_INT32):				return GL_RGB32UI;
		case FMT_CASE(RGB,		UNORM_INT16):					return GL_RGB16;
		case FMT_CASE(RGB,		SNORM_INT16):					return GL_RGB16_SNORM;
		case FMT_CASE(RGB,		HALF_FLOAT):					return GL_RGB16F;
		case FMT_CASE(RGB,		SIGNED_INT16):					return GL_RGB16I;
		case FMT_CASE(RGB,		UNSIGNED_INT16):				return GL_RGB16UI;
		case FMT_CASE(RGB,		SNORM_INT8):					return GL_RGB8_SNORM;
		case FMT_CASE(RGB,		SIGNED_INT8):					return GL_RGB8I;
		case FMT_CASE(RGB,		UNSIGNED_INT8):					return GL_RGB8UI;
		case FMT_CASE(sRGB,		UNORM_INT8):					return GL_SRGB8;
		case FMT_CASE(RGB,		UNSIGNED_INT_999_E5_REV):		return GL_RGB9_E5;
		case FMT_CASE(RGB,		UNORM_INT_1010102_REV):			return GL_RGB10;

		case FMT_CASE(RG,		FLOAT):							return GL_RG32F;
		case FMT_CASE(RG,		SIGNED_INT32):					return GL_RG32I;
		case FMT_CASE(RG,		UNSIGNED_INT32):				return GL_RG32UI;
		case FMT_CASE(RG,		UNORM_INT16):					return GL_RG16;
		case FMT_CASE(RG,		SNORM_INT16):					return GL_RG16_SNORM;
		case FMT_CASE(RG,		HALF_FLOAT):					return GL_RG16F;
		case FMT_CASE(RG,		SIGNED_INT16):					return GL_RG16I;
		case FMT_CASE(RG,		UNSIGNED_INT16):				return GL_RG16UI;
		case FMT_CASE(RG,		UNORM_INT8):					return GL_RG8;
		case FMT_CASE(RG,		SIGNED_INT8):					return GL_RG8I;
		case FMT_CASE(RG,		UNSIGNED_INT8):					return GL_RG8UI;
		case FMT_CASE(RG,		SNORM_INT8):					return GL_RG8_SNORM;
		case FMT_CASE(sRG,		UNORM_INT8):					return GL_SRG8_EXT;

		case FMT_CASE(R,		FLOAT):							return GL_R32F;
		case FMT_CASE(R,		SIGNED_INT32):					return GL_R32I;
		case FMT_CASE(R,		UNSIGNED_INT32):				return GL_R32UI;
		case FMT_CASE(R,		UNORM_INT16):					return GL_R16;
		case FMT_CASE(R,		SNORM_INT16):					return GL_R16_SNORM;
		case FMT_CASE(R,		HALF_FLOAT):					return GL_R16F;
		case FMT_CASE(R,		SIGNED_INT16):					return GL_R16I;
		case FMT_CASE(R,		UNSIGNED_INT16):				return GL_R16UI;
		case FMT_CASE(R,		UNORM_INT8):					return GL_R8;
		case FMT_CASE(R,		SIGNED_INT8):					return GL_R8I;
		case FMT_CASE(R,		UNSIGNED_INT8):					return GL_R8UI;
		case FMT_CASE(R,		SNORM_INT8):					return GL_R8_SNORM;
		case FMT_CASE(sR,		UNORM_INT8):					return GL_SR8_EXT;

		case FMT_CASE(D,		FLOAT):							return GL_DEPTH_COMPONENT32F;
		case FMT_CASE(D,		UNSIGNED_INT_24_8):				return GL_DEPTH_COMPONENT24;
		case FMT_CASE(D,		UNSIGNED_INT32):				return GL_DEPTH_COMPONENT32;
		case FMT_CASE(DS,		FLOAT_UNSIGNED_INT_24_8_REV):	return GL_DEPTH32F_STENCIL8;
		case FMT_CASE(DS,		UNSIGNED_INT_24_8):				return GL_DEPTH24_STENCIL8;

		default:
			throw tcu::InternalError("Can't map texture format to GL internal format");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Map generic compressed format to GL compressed format enum.
 *
 * Maps generic compressed format to GL compressed format enum value.
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param format Generic compressed format.
 * \return GL compressed texture format.
 *//*--------------------------------------------------------------------*/
deUint32 getGLFormat (tcu::CompressedTexFormat format)
{
	switch (format)
	{
		case tcu::COMPRESSEDTEXFORMAT_ETC1_RGB8:						return GL_ETC1_RGB8_OES;
		case tcu::COMPRESSEDTEXFORMAT_EAC_R11:							return GL_COMPRESSED_R11_EAC;
		case tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_R11:					return GL_COMPRESSED_SIGNED_R11_EAC;
		case tcu::COMPRESSEDTEXFORMAT_EAC_RG11:							return GL_COMPRESSED_RG11_EAC;
		case tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11:					return GL_COMPRESSED_SIGNED_RG11_EAC;
		case tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8:						return GL_COMPRESSED_RGB8_ETC2;
		case tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8:						return GL_COMPRESSED_SRGB8_ETC2;
		case tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:	return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
		case tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:	return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
		case tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8:					return GL_COMPRESSED_RGBA8_ETC2_EAC;
		case tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;

		case tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA:					return GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA:					return GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA:					return GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA:					return GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA:					return GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA:					return GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA:					return GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA:					return GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA:					return GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA:					return GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA:					return GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA:					return GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA:					return GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA:					return GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR;
		case tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8:			return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;

		default:
			throw tcu::InternalError("Can't map compressed format to GL format");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Map compressed GL format to generic compressed format.
 *
 * Maps compressed GL format to generic compressed format.
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param GL compressed texture format.
 * \return format Generic compressed format.
 *//*--------------------------------------------------------------------*/
tcu::CompressedTexFormat mapGLCompressedTexFormat (deUint32 format)
{
	switch (format)
	{
		case GL_ETC1_RGB8_OES:								return tcu::COMPRESSEDTEXFORMAT_ETC1_RGB8;
		case GL_COMPRESSED_R11_EAC:							return tcu::COMPRESSEDTEXFORMAT_EAC_R11;
		case GL_COMPRESSED_SIGNED_R11_EAC:					return tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_R11;
		case GL_COMPRESSED_RG11_EAC:						return tcu::COMPRESSEDTEXFORMAT_EAC_RG11;
		case GL_COMPRESSED_SIGNED_RG11_EAC:					return tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11;
		case GL_COMPRESSED_RGB8_ETC2:						return tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8;
		case GL_COMPRESSED_SRGB8_ETC2:						return tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8;
		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:	return tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1;
		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:	return tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1;
		case GL_COMPRESSED_RGBA8_ETC2_EAC:					return tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:			return tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8;

		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA;
		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:				return tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8;
		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:		return tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8;

		default:
			throw tcu::InternalError("Can't map compressed GL format to compressed format");
	}
}

bool isCompressedFormat (deUint32 internalFormat)
{
	switch (internalFormat)
	{
		case GL_ETC1_RGB8_OES:
		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;
	}
}

static tcu::TextureFormat::ChannelType mapGLChannelType (deUint32 dataType, bool normalized)
{
	// \note Normalized bit is ignored where it doesn't apply.
	using tcu::TextureFormat;

	switch (dataType)
	{
		case GL_UNSIGNED_BYTE:					return normalized ? TextureFormat::UNORM_INT8	: TextureFormat::UNSIGNED_INT8;
		case GL_BYTE:							return normalized ? TextureFormat::SNORM_INT8	: TextureFormat::SIGNED_INT8;
		case GL_UNSIGNED_SHORT:					return normalized ? TextureFormat::UNORM_INT16	: TextureFormat::UNSIGNED_INT16;
		case GL_SHORT:							return normalized ? TextureFormat::SNORM_INT16	: TextureFormat::SIGNED_INT16;
		case GL_UNSIGNED_INT:					return normalized ? TextureFormat::UNORM_INT32	: TextureFormat::UNSIGNED_INT32;
		case GL_INT:							return normalized ? TextureFormat::SNORM_INT32	: TextureFormat::SIGNED_INT32;
		case GL_FLOAT:							return TextureFormat::FLOAT;
		case GL_UNSIGNED_SHORT_4_4_4_4:			return TextureFormat::UNORM_SHORT_4444;
		case GL_UNSIGNED_SHORT_5_5_5_1:			return TextureFormat::UNORM_SHORT_5551;
		case GL_UNSIGNED_SHORT_5_6_5:			return TextureFormat::UNORM_SHORT_565;
		case GL_HALF_FLOAT:						return TextureFormat::HALF_FLOAT;
		case GL_UNSIGNED_INT_2_10_10_10_REV:	return normalized ? TextureFormat::UNORM_INT_1010102_REV : TextureFormat::UNSIGNED_INT_1010102_REV;
		case GL_UNSIGNED_INT_10F_11F_11F_REV:	return TextureFormat::UNSIGNED_INT_11F_11F_10F_REV;
		case GL_UNSIGNED_INT_24_8:				return TextureFormat::UNSIGNED_INT_24_8;
		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:	return TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV;
		case GL_UNSIGNED_INT_5_9_9_9_REV:		return TextureFormat::UNSIGNED_INT_999_E5_REV;

		default:
			DE_ASSERT(false);
			return TextureFormat::CHANNELTYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Map GL pixel transfer format to tcu::TextureFormat.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param format	GL pixel format.
 * \param dataType	GL data type.
 * \return Generic texture format.
 *//*--------------------------------------------------------------------*/
tcu::TextureFormat mapGLTransferFormat (deUint32 format, deUint32 dataType)
{
	using tcu::TextureFormat;
	switch (format)
	{
		case GL_ALPHA:				return TextureFormat(TextureFormat::A,		mapGLChannelType(dataType, true));
		case GL_LUMINANCE:			return TextureFormat(TextureFormat::L,		mapGLChannelType(dataType, true));
		case GL_LUMINANCE_ALPHA:	return TextureFormat(TextureFormat::LA,		mapGLChannelType(dataType, true));
		case GL_RGB:				return TextureFormat(TextureFormat::RGB,	mapGLChannelType(dataType, true));
		case GL_RGBA:				return TextureFormat(TextureFormat::RGBA,	mapGLChannelType(dataType, true));
		case GL_BGRA:				return TextureFormat(TextureFormat::BGRA,	mapGLChannelType(dataType, true));
		case GL_RG:					return TextureFormat(TextureFormat::RG,		mapGLChannelType(dataType, true));
		case GL_RED:				return TextureFormat(TextureFormat::R,		mapGLChannelType(dataType, true));
		case GL_RGBA_INTEGER:		return TextureFormat(TextureFormat::RGBA,	mapGLChannelType(dataType, false));
		case GL_RGB_INTEGER:		return TextureFormat(TextureFormat::RGB,	mapGLChannelType(dataType, false));
		case GL_RG_INTEGER:			return TextureFormat(TextureFormat::RG,		mapGLChannelType(dataType, false));
		case GL_RED_INTEGER:		return TextureFormat(TextureFormat::R,		mapGLChannelType(dataType, false));

		case GL_DEPTH_COMPONENT:	return TextureFormat(TextureFormat::D,		mapGLChannelType(dataType, true));
		case GL_DEPTH_STENCIL:		return TextureFormat(TextureFormat::DS,		mapGLChannelType(dataType, true));

		default:
			throw tcu::InternalError(string("Can't map GL pixel format (") + tcu::toHex(format).toString() + ", " + tcu::toHex(dataType).toString() + ") to texture format");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Map GL internal texture format to tcu::TextureFormat.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param internalFormat Sized internal format.
 * \return Generic texture format.
 *//*--------------------------------------------------------------------*/
tcu::TextureFormat mapGLInternalFormat (deUint32 internalFormat)
{
	using tcu::TextureFormat;
	switch (internalFormat)
	{
		case GL_RGB5_A1:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_SHORT_5551);
		case GL_RGBA4:				return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_SHORT_4444);
		case GL_RGB565:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_SHORT_565);
		case GL_DEPTH_COMPONENT16:	return TextureFormat(TextureFormat::D,		TextureFormat::UNORM_INT16);
		case GL_STENCIL_INDEX8:		return TextureFormat(TextureFormat::S,		TextureFormat::UNSIGNED_INT8);

		case GL_RGBA32F:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::FLOAT);
		case GL_RGBA32I:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT32);
		case GL_RGBA32UI:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT32);
		case GL_RGBA16:				return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT16);
		case GL_RGBA16_SNORM:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT16);
		case GL_RGBA16F:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::HALF_FLOAT);
		case GL_RGBA16I:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT16);
		case GL_RGBA16UI:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT16);
		case GL_RGBA8:				return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
		case GL_RGBA8I:				return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT8);
		case GL_RGBA8UI:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT8);
		case GL_SRGB8_ALPHA8:		return TextureFormat(TextureFormat::sRGBA,	TextureFormat::UNORM_INT8);
		case GL_RGB10_A2:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT_1010102_REV);
		case GL_RGB10_A2UI:			return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT_1010102_REV);
		case GL_RGBA8_SNORM:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT8);

		case GL_RGB8:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
		case GL_R11F_G11F_B10F:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT_11F_11F_10F_REV);
		case GL_RGB32F:				return TextureFormat(TextureFormat::RGB,	TextureFormat::FLOAT);
		case GL_RGB32I:				return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT32);
		case GL_RGB32UI:			return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT32);
		case GL_RGB16:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT16);
		case GL_RGB16_SNORM:		return TextureFormat(TextureFormat::RGB,	TextureFormat::SNORM_INT16);
		case GL_RGB16F:				return TextureFormat(TextureFormat::RGB,	TextureFormat::HALF_FLOAT);
		case GL_RGB16I:				return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT16);
		case GL_RGB16UI:			return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT16);
		case GL_RGB8_SNORM:			return TextureFormat(TextureFormat::RGB,	TextureFormat::SNORM_INT8);
		case GL_RGB8I:				return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT8);
		case GL_RGB8UI:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT8);
		case GL_SRGB8:				return TextureFormat(TextureFormat::sRGB,	TextureFormat::UNORM_INT8);
		case GL_RGB9_E5:			return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT_999_E5_REV);
		case GL_RGB10:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT_1010102_REV);

		case GL_RG32F:				return TextureFormat(TextureFormat::RG,		TextureFormat::FLOAT);
		case GL_RG32I:				return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT32);
		case GL_RG32UI:				return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT32);
		case GL_RG16:				return TextureFormat(TextureFormat::RG,		TextureFormat::UNORM_INT16);
		case GL_RG16_SNORM:			return TextureFormat(TextureFormat::RG,		TextureFormat::SNORM_INT16);
		case GL_RG16F:				return TextureFormat(TextureFormat::RG,		TextureFormat::HALF_FLOAT);
		case GL_RG16I:				return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT16);
		case GL_RG16UI:				return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT16);
		case GL_RG8:				return TextureFormat(TextureFormat::RG,		TextureFormat::UNORM_INT8);
		case GL_RG8I:				return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT8);
		case GL_RG8UI:				return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT8);
		case GL_RG8_SNORM:			return TextureFormat(TextureFormat::RG,		TextureFormat::SNORM_INT8);
		case GL_SRG8_EXT:			return TextureFormat(TextureFormat::sRG,	TextureFormat::UNORM_INT8);

		case GL_R32F:				return TextureFormat(TextureFormat::R,		TextureFormat::FLOAT);
		case GL_R32I:				return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT32);
		case GL_R32UI:				return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT32);
		case GL_R16:				return TextureFormat(TextureFormat::R,		TextureFormat::UNORM_INT16);
		case GL_R16_SNORM:			return TextureFormat(TextureFormat::R,		TextureFormat::SNORM_INT16);
		case GL_R16F:				return TextureFormat(TextureFormat::R,		TextureFormat::HALF_FLOAT);
		case GL_R16I:				return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT16);
		case GL_R16UI:				return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT16);
		case GL_R8:					return TextureFormat(TextureFormat::R,		TextureFormat::UNORM_INT8);
		case GL_R8I:				return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT8);
		case GL_R8UI:				return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT8);
		case GL_R8_SNORM:			return TextureFormat(TextureFormat::R,		TextureFormat::SNORM_INT8);
		case GL_SR8_EXT:			return TextureFormat(TextureFormat::sR,		TextureFormat::UNORM_INT8);

		case GL_DEPTH_COMPONENT32F:	return TextureFormat(TextureFormat::D,		TextureFormat::FLOAT);
		case GL_DEPTH_COMPONENT24:	return TextureFormat(TextureFormat::D,		TextureFormat::UNSIGNED_INT_24_8);
		case GL_DEPTH_COMPONENT32:	return TextureFormat(TextureFormat::D,		TextureFormat::UNSIGNED_INT32);
		case GL_DEPTH32F_STENCIL8:	return TextureFormat(TextureFormat::DS,		TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV);
		case GL_DEPTH24_STENCIL8:	return TextureFormat(TextureFormat::DS,		TextureFormat::UNSIGNED_INT_24_8);

		default:
			throw tcu::InternalError(string("Can't map GL sized internal format (") + tcu::toHex(internalFormat).toString() + ") to texture format");
	}
}

bool isGLInternalColorFormatFilterable (deUint32 format)
{
	switch (format)
	{
		case GL_R8:
		case GL_R8_SNORM:
		case GL_RG8:
		case GL_RG8_SNORM:
		case GL_RGB8:
		case GL_RGB8_SNORM:
		case GL_RGB565:
		case GL_RGBA4:
		case GL_RGB5_A1:
		case GL_RGBA8:
		case GL_RGBA8_SNORM:
		case GL_RGB10_A2:
		case GL_SR8_EXT:
		case GL_SRG8_EXT:
		case GL_SRGB8:
		case GL_SRGB8_ALPHA8:
		case GL_R16F:
		case GL_RG16F:
		case GL_RGB16F:
		case GL_RGBA16F:
		case GL_R11F_G11F_B10F:
		case GL_RGB9_E5:
			return true;

		case GL_RGB10_A2UI:
		case GL_R32F:
		case GL_RG32F:
		case GL_RGB32F:
		case GL_RGBA32F:
		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_RGB8I:
		case GL_RGB8UI:
		case GL_RGB16I:
		case GL_RGB16UI:
		case GL_RGB32I:
		case GL_RGB32UI:
		case GL_RGBA8I:
		case GL_RGBA8UI:
		case GL_RGBA16I:
		case GL_RGBA16UI:
		case GL_RGBA32I:
		case GL_RGBA32UI:
			return false;

		default:
			DE_ASSERT(false);
			return false;
	}
}

static inline tcu::Sampler::WrapMode mapGLWrapMode (deUint32 wrapMode)
{
	switch (wrapMode)
	{
		case GL_CLAMP_TO_EDGE:		return tcu::Sampler::CLAMP_TO_EDGE;
		case GL_CLAMP_TO_BORDER:	return tcu::Sampler::CLAMP_TO_BORDER;
		case GL_REPEAT:				return tcu::Sampler::REPEAT_GL;
		case GL_MIRRORED_REPEAT:	return tcu::Sampler::MIRRORED_REPEAT_GL;
		default:
			throw tcu::InternalError("Can't map GL wrap mode " + tcu::toHex(wrapMode).toString());
	}
}

static inline tcu::Sampler::FilterMode mapGLMinFilterMode (deUint32 filterMode)
{
	switch (filterMode)
	{
		case GL_NEAREST:				return tcu::Sampler::NEAREST;
		case GL_LINEAR:					return tcu::Sampler::LINEAR;
		case GL_NEAREST_MIPMAP_NEAREST:	return tcu::Sampler::NEAREST_MIPMAP_NEAREST;
		case GL_NEAREST_MIPMAP_LINEAR:	return tcu::Sampler::NEAREST_MIPMAP_LINEAR;
		case GL_LINEAR_MIPMAP_NEAREST:	return tcu::Sampler::LINEAR_MIPMAP_NEAREST;
		case GL_LINEAR_MIPMAP_LINEAR:	return tcu::Sampler::LINEAR_MIPMAP_LINEAR;
		default:
			throw tcu::InternalError("Can't map GL min filter mode" + tcu::toHex(filterMode).toString());
	}
}

static inline tcu::Sampler::FilterMode mapGLMagFilterMode (deUint32 filterMode)
{
	switch (filterMode)
	{
		case GL_NEAREST:				return tcu::Sampler::NEAREST;
		case GL_LINEAR:					return tcu::Sampler::LINEAR;
		default:
			throw tcu::InternalError("Can't map GL mag filter mode" + tcu::toHex(filterMode).toString());
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Map GL sampler parameters to tcu::Sampler.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param wrapS		S-component wrap mode
 * \param minFilter	Minification filter mode
 * \param magFilter	Magnification filter mode
 * \return Sampler description.
 *//*--------------------------------------------------------------------*/
tcu::Sampler mapGLSampler (deUint32 wrapS, deUint32 minFilter, deUint32 magFilter)
{
	return mapGLSampler(wrapS, wrapS, wrapS, minFilter, magFilter);
}


/*--------------------------------------------------------------------*//*!
 * \brief Map GL sampler parameters to tcu::Sampler.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param wrapS		S-component wrap mode
 * \param wrapT		T-component wrap mode
 * \param minFilter	Minification filter mode
 * \param magFilter	Magnification filter mode
 * \return Sampler description.
 *//*--------------------------------------------------------------------*/
tcu::Sampler mapGLSampler (deUint32 wrapS, deUint32 wrapT, deUint32 minFilter, deUint32 magFilter)
{
	return mapGLSampler(wrapS, wrapT, wrapS, minFilter, magFilter);
}

/*--------------------------------------------------------------------*//*!
 * \brief Map GL sampler parameters to tcu::Sampler.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param wrapS		S-component wrap mode
 * \param wrapT		T-component wrap mode
 * \param wrapR		R-component wrap mode
 * \param minFilter	Minification filter mode
 * \param magFilter	Magnification filter mode
 * \return Sampler description.
 *//*--------------------------------------------------------------------*/
tcu::Sampler mapGLSampler (deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 minFilter, deUint32 magFilter)
{
	return tcu::Sampler(mapGLWrapMode(wrapS), mapGLWrapMode(wrapT), mapGLWrapMode(wrapR),
						mapGLMinFilterMode(minFilter), mapGLMagFilterMode(magFilter),
						0.0f /* lod threshold */,
						true /* normalized coords */,
						tcu::Sampler::COMPAREMODE_NONE /* no compare */,
						0 /* compare channel */,
						tcu::Vec4(0.0f) /* border color, not used */);
}

/*--------------------------------------------------------------------*//*!
 * \brief Map GL compare function to tcu::Sampler::CompareMode.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param mode GL compare mode
 * \return Compare mode
 *//*--------------------------------------------------------------------*/
tcu::Sampler::CompareMode mapGLCompareFunc (deUint32 mode)
{
	switch (mode)
	{
		case GL_LESS:		return tcu::Sampler::COMPAREMODE_LESS;
		case GL_LEQUAL:		return tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL;
		case GL_GREATER:	return tcu::Sampler::COMPAREMODE_GREATER;
		case GL_GEQUAL:		return tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL;
		case GL_EQUAL:		return tcu::Sampler::COMPAREMODE_EQUAL;
		case GL_NOTEQUAL:	return tcu::Sampler::COMPAREMODE_NOT_EQUAL;
		case GL_ALWAYS:		return tcu::Sampler::COMPAREMODE_ALWAYS;
		case GL_NEVER:		return tcu::Sampler::COMPAREMODE_NEVER;
		default:
			throw tcu::InternalError("Can't map GL compare mode " + tcu::toHex(mode).toString());
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GL wrap mode.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param wrapMode Wrap mode
 * \return GL wrap mode
 *//*--------------------------------------------------------------------*/
deUint32 getGLWrapMode (tcu::Sampler::WrapMode wrapMode)
{
	DE_ASSERT(wrapMode != tcu::Sampler::WRAPMODE_LAST);
	switch (wrapMode)
	{
		case tcu::Sampler::CLAMP_TO_EDGE:		return GL_CLAMP_TO_EDGE;
		case tcu::Sampler::CLAMP_TO_BORDER:		return GL_CLAMP_TO_BORDER;
		case tcu::Sampler::REPEAT_GL:			return GL_REPEAT;
		case tcu::Sampler::MIRRORED_REPEAT_GL:	return GL_MIRRORED_REPEAT;
		default:
			throw tcu::InternalError("Can't map wrap mode");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GL filter mode.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param filterMode Filter mode
 * \return GL filter mode
 *//*--------------------------------------------------------------------*/
deUint32 getGLFilterMode (tcu::Sampler::FilterMode filterMode)
{
	DE_ASSERT(filterMode != tcu::Sampler::FILTERMODE_LAST);
	switch (filterMode)
	{
		case tcu::Sampler::NEAREST:					return GL_NEAREST;
		case tcu::Sampler::LINEAR:					return GL_LINEAR;
		case tcu::Sampler::NEAREST_MIPMAP_NEAREST:	return GL_NEAREST_MIPMAP_NEAREST;
		case tcu::Sampler::NEAREST_MIPMAP_LINEAR:	return GL_NEAREST_MIPMAP_LINEAR;
		case tcu::Sampler::LINEAR_MIPMAP_NEAREST:	return GL_LINEAR_MIPMAP_NEAREST;
		case tcu::Sampler::LINEAR_MIPMAP_LINEAR:	return GL_LINEAR_MIPMAP_LINEAR;
		default:
			throw tcu::InternalError("Can't map filter mode");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GL compare mode.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param compareMode Compare mode
 * \return GL compare mode
 *//*--------------------------------------------------------------------*/
deUint32 getGLCompareFunc (tcu::Sampler::CompareMode compareMode)
{
	DE_ASSERT(compareMode != tcu::Sampler::COMPAREMODE_NONE);
	switch (compareMode)
	{
		case tcu::Sampler::COMPAREMODE_NONE:				return GL_NONE;
		case tcu::Sampler::COMPAREMODE_LESS:				return GL_LESS;
		case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL:		return GL_LEQUAL;
		case tcu::Sampler::COMPAREMODE_GREATER:				return GL_GREATER;
		case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL:	return GL_GEQUAL;
		case tcu::Sampler::COMPAREMODE_EQUAL:				return GL_EQUAL;
		case tcu::Sampler::COMPAREMODE_NOT_EQUAL:			return GL_NOTEQUAL;
		case tcu::Sampler::COMPAREMODE_ALWAYS:				return GL_ALWAYS;
		case tcu::Sampler::COMPAREMODE_NEVER:				return GL_NEVER;
		default:
			throw tcu::InternalError("Can't map compare mode");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GL cube face.
 *
 * If no mapping is found, throws tcu::InternalError.
 *
 * \param face Cube face
 * \return GL cube face
 *//*--------------------------------------------------------------------*/
deUint32 getGLCubeFace (tcu::CubeFace face)
{
	DE_ASSERT(face != tcu::CUBEFACE_LAST);
	switch (face)
	{
		case tcu::CUBEFACE_NEGATIVE_X:	return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
		case tcu::CUBEFACE_POSITIVE_X:	return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
		case tcu::CUBEFACE_NEGATIVE_Y:	return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
		case tcu::CUBEFACE_POSITIVE_Y:	return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
		case tcu::CUBEFACE_NEGATIVE_Z:	return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
		case tcu::CUBEFACE_POSITIVE_Z:	return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
		default:
			throw tcu::InternalError("Can't map cube face");
	}
}

tcu::CubeFace getCubeFaceFromGL (deUint32 face)
{
	switch (face)
	{
		case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:	return tcu::CUBEFACE_NEGATIVE_X;
		case GL_TEXTURE_CUBE_MAP_POSITIVE_X:	return tcu::CUBEFACE_POSITIVE_X;
		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:	return tcu::CUBEFACE_NEGATIVE_Y;
		case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:	return tcu::CUBEFACE_POSITIVE_Y;
		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:	return tcu::CUBEFACE_NEGATIVE_Z;
		case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:	return tcu::CUBEFACE_POSITIVE_Z;
		default:
			throw tcu::InternalError("Can't map cube face");
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL 1D sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSampler1DType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_1D;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_1D;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_1D;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_1D;

		default:
			return glu::TYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL 2D sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSampler2DType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_2D;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_2D;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_2D;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_2D;

		default:
			return glu::TYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL cube map sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSamplerCubeType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_CUBE;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_CUBE;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_CUBE;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_CUBE;

		default:
			return glu::TYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL 1D array sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSampler1DArrayType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_1D_ARRAY;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_1D_ARRAY;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_1D_ARRAY;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_1D_ARRAY;

		default:
			return glu::TYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL 2D array sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSampler2DArrayType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_2D_ARRAY;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_2D_ARRAY;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_2D_ARRAY;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_2D_ARRAY;

		default:
			return glu::TYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL 3D sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSampler3DType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_3D;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_3D;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_3D;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_3D;

		default:
			return glu::TYPE_LAST;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Get GLSL sampler type for texture format.
 *
 * If no mapping is found, glu::TYPE_LAST is returned.
 *
 * \param format Texture format
 * \return GLSL cube map array sampler type for format
 *//*--------------------------------------------------------------------*/
DataType getSamplerCubeArrayType (tcu::TextureFormat format)
{
	using tcu::TextureFormat;

	if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
		return TYPE_SAMPLER_CUBE_ARRAY;

	if (format.order == TextureFormat::S)
		return TYPE_LAST;

	switch (tcu::getTextureChannelClass(format.type))
	{
		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
			return glu::TYPE_SAMPLER_CUBE_ARRAY;

		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
			return glu::TYPE_INT_SAMPLER_CUBE_ARRAY;

		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
			return glu::TYPE_UINT_SAMPLER_CUBE_ARRAY;

		default:
			return glu::TYPE_LAST;
	}
}

enum RenderableType
{
	RENDERABLE_COLOR	= (1<<0),
	RENDERABLE_DEPTH	= (1<<1),
	RENDERABLE_STENCIL	= (1<<2)
};

static deUint32 getRenderableBitsES3 (const ContextInfo& contextInfo, deUint32 internalFormat)
{
	switch (internalFormat)
	{
		// Color-renderable formats
		case GL_RGBA32I:
		case GL_RGBA32UI:
		case GL_RGBA16I:
		case GL_RGBA16UI:
		case GL_RGBA8:
		case GL_RGBA8I:
		case GL_RGBA8UI:
		case GL_SRGB8_ALPHA8:
		case GL_RGB10_A2:
		case GL_RGB10_A2UI:
		case GL_RGBA4:
		case GL_RGB5_A1:
		case GL_RGB8:
		case GL_RGB565:
		case GL_RG32I:
		case GL_RG32UI:
		case GL_RG16I:
		case GL_RG16UI:
		case GL_RG8:
		case GL_RG8I:
		case GL_RG8UI:
		case GL_R32I:
		case GL_R32UI:
		case GL_R16I:
		case GL_R16UI:
		case GL_R8:
		case GL_R8I:
		case GL_R8UI:
			return RENDERABLE_COLOR;

		// GL_EXT_color_buffer_float
		case GL_RGBA32F:
		case GL_R11F_G11F_B10F:
		case GL_RG32F:
		case GL_R32F:
			if (contextInfo.isExtensionSupported("GL_EXT_color_buffer_float"))
				return RENDERABLE_COLOR;
			else
				return 0;

		// GL_EXT_color_buffer_float / GL_EXT_color_buffer_half_float
		case GL_RGBA16F:
		case GL_RG16F:
		case GL_R16F:
			if (contextInfo.isExtensionSupported("GL_EXT_color_buffer_float") ||
				contextInfo.isExtensionSupported("GL_EXT_color_buffer_half_float"))
				return RENDERABLE_COLOR;
			else
				return 0;

		// Depth formats
		case GL_DEPTH_COMPONENT32F:
		case GL_DEPTH_COMPONENT24:
		case GL_DEPTH_COMPONENT16:
			return RENDERABLE_DEPTH;

		// Depth+stencil formats
		case GL_DEPTH32F_STENCIL8:
		case GL_DEPTH24_STENCIL8:
			return RENDERABLE_DEPTH|RENDERABLE_STENCIL;

		// Stencil formats
		case GL_STENCIL_INDEX8:
			return RENDERABLE_STENCIL;

		default:
			return 0;
	}
}

/*--------------------------------------------------------------------*//*!
 * \brief Check if sized internal format is color-renderable.
 * \note Works currently only on ES3 context.
 *//*--------------------------------------------------------------------*/
bool isSizedFormatColorRenderable (const RenderContext& renderCtx, const ContextInfo& contextInfo, deUint32 sizedFormat)
{
	deUint32 renderable = 0;

	if (renderCtx.getType().getAPI() == ApiType::es(3,0))
		renderable = getRenderableBitsES3(contextInfo, sizedFormat);
	else
		throw tcu::InternalError("Context type not supported in query");

	return (renderable & RENDERABLE_COLOR) != 0;
}

const tcu::IVec2 (&getDefaultGatherOffsets (void))[4]
{
	static const tcu::IVec2 s_defaultOffsets[4] =
	{
		tcu::IVec2(0, 1),
		tcu::IVec2(1, 1),
		tcu::IVec2(1, 0),
		tcu::IVec2(0, 0),
	};
	return s_defaultOffsets;
}

tcu::PixelBufferAccess getTextureBufferEffectiveRefTexture (TextureBuffer& buffer, int maxTextureBufferSize)
{
	DE_ASSERT(maxTextureBufferSize > 0);

	const tcu::PixelBufferAccess& fullAccess = buffer.getFullRefTexture();

	return tcu::PixelBufferAccess(fullAccess.getFormat(),
								  tcu::IVec3(de::min(fullAccess.getWidth(), maxTextureBufferSize), 1, 1),
								  fullAccess.getPitch(),
								  fullAccess.getDataPtr());
}

tcu::ConstPixelBufferAccess getTextureBufferEffectiveRefTexture (const TextureBuffer& buffer, int maxTextureBufferSize)
{
	return getTextureBufferEffectiveRefTexture(const_cast<TextureBuffer&>(buffer), maxTextureBufferSize);
}

} // glu