Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Tester Core
      3  * ----------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Texture utilities.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuTextureUtil.hpp"
     25 #include "tcuVectorUtil.hpp"
     26 #include "deRandom.hpp"
     27 #include "deMath.h"
     28 #include "deMemory.h"
     29 
     30 #include <limits>
     31 
     32 namespace tcu
     33 {
     34 
     35 static inline float sRGBChannelToLinear (float cs)
     36 {
     37 	if (cs <= 0.04045)
     38 		return cs / 12.92f;
     39 	else
     40 		return deFloatPow((cs + 0.055f) / 1.055f, 2.4f);
     41 }
     42 
     43 static inline float linearChannelToSRGB (float cl)
     44 {
     45 	if (cl <= 0.0f)
     46 		return 0.0f;
     47 	else if (cl < 0.0031308f)
     48 		return 12.92f*cl;
     49 	else if (cl < 1.0f)
     50 		return 1.055f*deFloatPow(cl, 0.41666f) - 0.055f;
     51 	else
     52 		return 1.0f;
     53 }
     54 
     55 //! Convert sRGB to linear colorspace
     56 Vec4 sRGBToLinear (const Vec4& cs)
     57 {
     58 	return Vec4(sRGBChannelToLinear(cs[0]),
     59 				sRGBChannelToLinear(cs[1]),
     60 				sRGBChannelToLinear(cs[2]),
     61 				cs[3]);
     62 }
     63 
     64 //! Convert from linear to sRGB colorspace
     65 Vec4 linearToSRGB (const Vec4& cl)
     66 {
     67 	return Vec4(linearChannelToSRGB(cl[0]),
     68 				linearChannelToSRGB(cl[1]),
     69 				linearChannelToSRGB(cl[2]),
     70 				cl[3]);
     71 }
     72 
     73 bool isSRGB (TextureFormat format)
     74 {
     75 	return	format.order == TextureFormat::sR	||
     76 			format.order == TextureFormat::sRG	||
     77 			format.order == TextureFormat::sRGB	||
     78 			format.order == TextureFormat::sRGBA;
     79 }
     80 
     81 bool isCombinedDepthStencilType (TextureFormat::ChannelType type)
     82 {
     83 	// make sure to update this if type table is updated
     84 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
     85 
     86 	return	type == TextureFormat::UNSIGNED_INT_24_8 ||
     87 			type == TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV;
     88 }
     89 
     90 //! Get texture channel class for format
     91 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
     92 {
     93 	// make sure this table is updated if format table is updated
     94 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
     95 
     96 	switch (channelType)
     97 	{
     98 		case TextureFormat::SNORM_INT8:						return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
     99 		case TextureFormat::SNORM_INT16:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
    100 		case TextureFormat::SNORM_INT32:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
    101 		case TextureFormat::UNORM_INT8:						return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    102 		case TextureFormat::UNORM_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    103 		case TextureFormat::UNORM_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    104 		case TextureFormat::UNORM_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    105 		case TextureFormat::UNORM_SHORT_565:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    106 		case TextureFormat::UNORM_SHORT_555:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    107 		case TextureFormat::UNORM_SHORT_4444:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    108 		case TextureFormat::UNORM_SHORT_5551:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    109 		case TextureFormat::UNORM_INT_101010:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    110 		case TextureFormat::UNORM_INT_1010102_REV:			return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
    111 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    112 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return TEXTURECHANNELCLASS_FLOATING_POINT;
    113 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return TEXTURECHANNELCLASS_FLOATING_POINT;
    114 		case TextureFormat::UNSIGNED_INT_24_8:				return TEXTURECHANNELCLASS_LAST;					//!< packed unorm24-uint8
    115 		case TextureFormat::SIGNED_INT8:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
    116 		case TextureFormat::SIGNED_INT16:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
    117 		case TextureFormat::SIGNED_INT32:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
    118 		case TextureFormat::UNSIGNED_INT8:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    119 		case TextureFormat::UNSIGNED_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    120 		case TextureFormat::UNSIGNED_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    121 		case TextureFormat::UNSIGNED_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    122 		case TextureFormat::HALF_FLOAT:						return TEXTURECHANNELCLASS_FLOATING_POINT;
    123 		case TextureFormat::FLOAT:							return TEXTURECHANNELCLASS_FLOATING_POINT;
    124 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return TEXTURECHANNELCLASS_LAST;					//!< packed float32-pad24-uint8
    125 		default:											return TEXTURECHANNELCLASS_LAST;
    126 	}
    127 }
    128 
    129 /*--------------------------------------------------------------------*//*!
    130  * \brief Get access to subregion of pixel buffer
    131  * \param access	Parent access object
    132  * \param x			X offset
    133  * \param y			Y offset
    134  * \param z			Z offset
    135  * \param width		Width
    136  * \param height	Height
    137  * \param depth		Depth
    138  * \return Access object that targets given subregion of parent access object
    139  *//*--------------------------------------------------------------------*/
    140 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
    141 {
    142 	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
    143 	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
    144 
    145 	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
    146 	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
    147 
    148 	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
    149 	DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
    150 
    151 	return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
    152 								  (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
    153 }
    154 
    155 /*--------------------------------------------------------------------*//*!
    156  * \brief Get access to subregion of pixel buffer
    157  * \param access	Parent access object
    158  * \param x			X offset
    159  * \param y			Y offset
    160  * \param z			Z offset
    161  * \param width		Width
    162  * \param height	Height
    163  * \param depth		Depth
    164  * \return Access object that targets given subregion of parent access object
    165  *//*--------------------------------------------------------------------*/
    166 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
    167 {
    168 	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
    169 	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
    170 
    171 	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
    172 	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
    173 
    174 	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
    175 	DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
    176 
    177 	return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
    178 							 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
    179 }
    180 
    181 /*--------------------------------------------------------------------*//*!
    182  * \brief Get access to subregion of pixel buffer
    183  * \param access	Parent access object
    184  * \param x			X offset
    185  * \param y			Y offset
    186  * \param width		Width
    187  * \param height	Height
    188  * \return Access object that targets given subregion of parent access object
    189  *//*--------------------------------------------------------------------*/
    190 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
    191 {
    192 	return getSubregion(access, x, y, 0, width, height, 1);
    193 }
    194 
    195 /*--------------------------------------------------------------------*//*!
    196  * \brief Get access to subregion of pixel buffer
    197  * \param access	Parent access object
    198  * \param x			X offset
    199  * \param y			Y offset
    200  * \param width		Width
    201  * \param height	Height
    202  * \return Access object that targets given subregion of parent access object
    203  *//*--------------------------------------------------------------------*/
    204 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
    205 {
    206 	return getSubregion(access, x, y, 0, width, height, 1);
    207 }
    208 
    209 /*--------------------------------------------------------------------*//*!
    210  * \brief Flip rows in Y direction
    211  * \param access Access object
    212  * \return Modified access object where Y coordinates are reversed
    213  *//*--------------------------------------------------------------------*/
    214 PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
    215 {
    216 	const int			rowPitch		= access.getRowPitch();
    217 	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
    218 	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
    219 
    220 	return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
    221 }
    222 
    223 /*--------------------------------------------------------------------*//*!
    224  * \brief Flip rows in Y direction
    225  * \param access Access object
    226  * \return Modified access object where Y coordinates are reversed
    227  *//*--------------------------------------------------------------------*/
    228 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
    229 {
    230 	const int			rowPitch		= access.getRowPitch();
    231 	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
    232 	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
    233 
    234 	return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
    235 }
    236 
    237 static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType)
    238 {
    239 	// make sure this table is updated if format table is updated
    240 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
    241 
    242 	float cMin = 0.0f;
    243 	float cMax = 0.0f;
    244 
    245 	switch (channelType)
    246 	{
    247 		// Signed normalized formats.
    248 		case TextureFormat::SNORM_INT8:
    249 		case TextureFormat::SNORM_INT16:
    250 		case TextureFormat::SNORM_INT32:					cMin = -1.0f;			cMax = 1.0f;			break;
    251 
    252 		// Unsigned normalized formats.
    253 		case TextureFormat::UNORM_INT8:
    254 		case TextureFormat::UNORM_INT16:
    255 		case TextureFormat::UNORM_INT24:
    256 		case TextureFormat::UNORM_INT32:
    257 		case TextureFormat::UNORM_SHORT_565:
    258 		case TextureFormat::UNORM_SHORT_4444:
    259 		case TextureFormat::UNORM_INT_101010:
    260 		case TextureFormat::UNORM_INT_1010102_REV:			cMin = 0.0f;			cMax = 1.0f;			break;
    261 
    262 		// Misc formats.
    263 		case TextureFormat::SIGNED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
    264 		case TextureFormat::SIGNED_INT16:					cMin = -32768.0f;		cMax = 32767.0f;		break;
    265 		case TextureFormat::SIGNED_INT32:					cMin = -2147483648.0f;	cMax = 2147483647.0f;	break;
    266 		case TextureFormat::UNSIGNED_INT8:					cMin = 0.0f;			cMax = 255.0f;			break;
    267 		case TextureFormat::UNSIGNED_INT16:					cMin = 0.0f;			cMax = 65535.0f;		break;
    268 		case TextureFormat::UNSIGNED_INT24:					cMin = 0.0f;			cMax = 16777215.0f;		break;
    269 		case TextureFormat::UNSIGNED_INT32:					cMin = 0.0f;			cMax = 4294967295.f;	break;
    270 		case TextureFormat::HALF_FLOAT:						cMin = -1e3f;			cMax = 1e3f;			break;
    271 		case TextureFormat::FLOAT:							cMin = -1e5f;			cMax = 1e5f;			break;
    272 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	cMin = 0.0f;			cMax = 1e4f;			break;
    273 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		cMin = 0.0f;			cMax = 1e5f;			break;
    274 
    275 		default:
    276 			DE_ASSERT(false);
    277 	}
    278 
    279 	return Vec2(cMin, cMax);
    280 }
    281 
    282 /*--------------------------------------------------------------------*//*!
    283  * \brief Get standard parameters for testing texture format
    284  *
    285  * Returns TextureFormatInfo that describes good parameters for exercising
    286  * given TextureFormat. Parameters include value ranges per channel and
    287  * suitable lookup scaling and bias in order to reduce result back to
    288  * 0..1 range.
    289  *//*--------------------------------------------------------------------*/
    290 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
    291 {
    292 	// Special cases.
    293 	if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV))
    294 		return TextureFormatInfo(Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f),
    295 								 Vec4(	 1023.0f,		 1023.0f,		 1023.0f,		 3.0f),
    296 								 Vec4(1.0f/1023.f,	1.0f/1023.0f,	1.0f/1023.0f,	1.0f/3.0f),
    297 								 Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f));
    298 	else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
    299 		return TextureFormatInfo(Vec4(0.0f,	0.0f,	0.0f,	0.0f),
    300 								 Vec4(1.0f,	1.0f,	1.0f,	0.0f),
    301 								 Vec4(1.0f,	1.0f,	1.0f,	1.0f),
    302 								 Vec4(0.0f,	0.0f,	0.0f,	0.0f)); // Depth / stencil formats.
    303 	else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
    304 		return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
    305 								 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
    306 								 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
    307 								 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
    308 
    309 	const Vec2						cRange		= getChannelValueRange(format.type);
    310 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
    311 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    312 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    313 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    314 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
    315 	const float						scale		= 1.0f / (cRange[1] - cRange[0]);
    316 	const float						bias		= -cRange[0] * scale;
    317 
    318 	return TextureFormatInfo(select(cRange[0],	0.0f, chnMask),
    319 							 select(cRange[1],	0.0f, chnMask),
    320 							 select(scale,		1.0f, chnMask),
    321 							 select(bias,		0.0f, chnMask));
    322 }
    323 
    324 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
    325 {
    326 	// make sure this table is updated if format table is updated
    327 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
    328 
    329 	switch (channelType)
    330 	{
    331 		case TextureFormat::SNORM_INT8:						return IVec4(8);
    332 		case TextureFormat::SNORM_INT16:					return IVec4(16);
    333 		case TextureFormat::SNORM_INT32:					return IVec4(32);
    334 		case TextureFormat::UNORM_INT8:						return IVec4(8);
    335 		case TextureFormat::UNORM_INT16:					return IVec4(16);
    336 		case TextureFormat::UNORM_INT24:					return IVec4(24);
    337 		case TextureFormat::UNORM_INT32:					return IVec4(32);
    338 		case TextureFormat::UNORM_SHORT_565:				return IVec4(5,6,5,0);
    339 		case TextureFormat::UNORM_SHORT_4444:				return IVec4(4);
    340 		case TextureFormat::UNORM_SHORT_555:				return IVec4(5,5,5,0);
    341 		case TextureFormat::UNORM_SHORT_5551:				return IVec4(5,5,5,1);
    342 		case TextureFormat::UNORM_INT_101010:				return IVec4(10,10,10,0);
    343 		case TextureFormat::UNORM_INT_1010102_REV:			return IVec4(10,10,10,2);
    344 		case TextureFormat::SIGNED_INT8:					return IVec4(8);
    345 		case TextureFormat::SIGNED_INT16:					return IVec4(16);
    346 		case TextureFormat::SIGNED_INT32:					return IVec4(32);
    347 		case TextureFormat::UNSIGNED_INT8:					return IVec4(8);
    348 		case TextureFormat::UNSIGNED_INT16:					return IVec4(16);
    349 		case TextureFormat::UNSIGNED_INT24:					return IVec4(24);
    350 		case TextureFormat::UNSIGNED_INT32:					return IVec4(32);
    351 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return IVec4(10,10,10,2);
    352 		case TextureFormat::UNSIGNED_INT_24_8:				return IVec4(24,8,0,0);
    353 		case TextureFormat::HALF_FLOAT:						return IVec4(16);
    354 		case TextureFormat::FLOAT:							return IVec4(32);
    355 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(11,11,10,0);
    356 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return IVec4(9,9,9,0);
    357 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(32,8,0,0);
    358 		default:
    359 			DE_ASSERT(false);
    360 			return IVec4(0);
    361 	}
    362 }
    363 
    364 IVec4 getTextureFormatBitDepth (const TextureFormat& format)
    365 {
    366 	const IVec4						chnBits		= getChannelBitDepth(format.type);
    367 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
    368 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    369 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    370 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    371 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
    372 	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
    373 														(chnMask[1]) ? ((int)map[1]) : (0),
    374 														(chnMask[2]) ? ((int)map[2]) : (0),
    375 														(chnMask[3]) ? ((int)map[3]) : (0));
    376 
    377 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
    378 }
    379 
    380 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
    381 {
    382 	// make sure this table is updated if format table is updated
    383 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
    384 
    385 	switch (channelType)
    386 	{
    387 		case TextureFormat::SNORM_INT8:
    388 		case TextureFormat::SNORM_INT16:
    389 		case TextureFormat::SNORM_INT32:
    390 		case TextureFormat::UNORM_INT8:
    391 		case TextureFormat::UNORM_INT16:
    392 		case TextureFormat::UNORM_INT24:
    393 		case TextureFormat::UNORM_INT32:
    394 		case TextureFormat::UNORM_SHORT_565:
    395 		case TextureFormat::UNORM_SHORT_4444:
    396 		case TextureFormat::UNORM_SHORT_555:
    397 		case TextureFormat::UNORM_SHORT_5551:
    398 		case TextureFormat::UNORM_INT_101010:
    399 		case TextureFormat::UNORM_INT_1010102_REV:
    400 		case TextureFormat::SIGNED_INT8:
    401 		case TextureFormat::SIGNED_INT16:
    402 		case TextureFormat::SIGNED_INT32:
    403 		case TextureFormat::UNSIGNED_INT8:
    404 		case TextureFormat::UNSIGNED_INT16:
    405 		case TextureFormat::UNSIGNED_INT24:
    406 		case TextureFormat::UNSIGNED_INT32:
    407 		case TextureFormat::UNSIGNED_INT_1010102_REV:
    408 		case TextureFormat::UNSIGNED_INT_24_8:
    409 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
    410 			return getChannelBitDepth(channelType);
    411 
    412 		case TextureFormat::HALF_FLOAT:						return IVec4(10);
    413 		case TextureFormat::FLOAT:							return IVec4(23);
    414 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(6,6,5,0);
    415 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(23,8,0,0);
    416 		default:
    417 			DE_ASSERT(false);
    418 			return IVec4(0);
    419 	}
    420 }
    421 
    422 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
    423 {
    424 	const IVec4						chnBits		= getChannelMantissaBitDepth(format.type);
    425 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
    426 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    427 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    428 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    429 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
    430 	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
    431 														(chnMask[1]) ? ((int)map[1]) : (0),
    432 														(chnMask[2]) ? ((int)map[2]) : (0),
    433 														(chnMask[3]) ? ((int)map[3]) : (0));
    434 
    435 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
    436 }
    437 
    438 BVec4 getTextureFormatChannelMask (const TextureFormat& format)
    439 {
    440 	const TextureSwizzle::Channel* const map = getChannelReadSwizzle(format.order).components;
    441 	return BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    442 				 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    443 				 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
    444 				 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
    445 }
    446 
    447 static inline float linearInterpolate (float t, float minVal, float maxVal)
    448 {
    449 	return minVal + (maxVal - minVal) * t;
    450 }
    451 
    452 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
    453 {
    454 	return a + (b - a) * t;
    455 }
    456 
    457 enum
    458 {
    459 	CLEAR_OPTIMIZE_THRESHOLD		= 128,
    460 	CLEAR_OPTIMIZE_MAX_PIXEL_SIZE	= 8
    461 };
    462 
    463 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
    464 {
    465 	DE_ASSERT(dst.getPixelPitch() == pixelSize); // only tightly packed
    466 
    467 	deUint8*	dstPtr	= (deUint8*)dst.getPixelPtr(0, y, z);
    468 	int			width	= dst.getWidth();
    469 
    470 	if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize))
    471 	{
    472 		deUint64 val;
    473 		memcpy(&val, pixel, sizeof(val));
    474 
    475 		for (int i = 0; i < width; i++)
    476 			((deUint64*)dstPtr)[i] = val;
    477 	}
    478 	else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize))
    479 	{
    480 		deUint32 val;
    481 		memcpy(&val, pixel, sizeof(val));
    482 
    483 		for (int i = 0; i < width; i++)
    484 			((deUint32*)dstPtr)[i] = val;
    485 	}
    486 	else
    487 	{
    488 		for (int i = 0; i < width; i++)
    489 			for (int j = 0; j < pixelSize; j++)
    490 				dstPtr[i*pixelSize+j] = pixel[j];
    491 	}
    492 }
    493 
    494 void clear (const PixelBufferAccess& access, const Vec4& color)
    495 {
    496 	const int	pixelSize				= access.getFormat().getPixelSize();
    497 	const int	pixelPitch				= access.getPixelPitch();
    498 	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
    499 
    500 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
    501 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
    502 	{
    503 		// Convert to destination format.
    504 		union
    505 		{
    506 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
    507 			deUint64	u64; // Forces 64-bit alignment.
    508 		} pixel;
    509 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
    510 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
    511 
    512 		for (int z = 0; z < access.getDepth(); z++)
    513 			for (int y = 0; y < access.getHeight(); y++)
    514 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
    515 	}
    516 	else
    517 	{
    518 		for (int z = 0; z < access.getDepth(); z++)
    519 			for (int y = 0; y < access.getHeight(); y++)
    520 				for (int x = 0; x < access.getWidth(); x++)
    521 					access.setPixel(color, x, y, z);
    522 	}
    523 }
    524 
    525 void clear (const PixelBufferAccess& access, const IVec4& color)
    526 {
    527 	const int	pixelSize				= access.getFormat().getPixelSize();
    528 	const int	pixelPitch				= access.getPixelPitch();
    529 	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
    530 
    531 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
    532 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
    533 	{
    534 		// Convert to destination format.
    535 		union
    536 		{
    537 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
    538 			deUint64	u64; // Forces 64-bit alignment.
    539 		} pixel;
    540 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
    541 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
    542 
    543 		for (int z = 0; z < access.getDepth(); z++)
    544 			for (int y = 0; y < access.getHeight(); y++)
    545 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
    546 	}
    547 	else
    548 	{
    549 		for (int z = 0; z < access.getDepth(); z++)
    550 			for (int y = 0; y < access.getHeight(); y++)
    551 				for (int x = 0; x < access.getWidth(); x++)
    552 					access.setPixel(color, x, y, z);
    553 	}
    554 }
    555 
    556 void clear (const PixelBufferAccess& access, const UVec4& color)
    557 {
    558 	clear(access, color.cast<deInt32>());
    559 }
    560 
    561 void clearDepth (const PixelBufferAccess& access, float depth)
    562 {
    563 	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::D);
    564 
    565 	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_DEPTH), tcu::Vec4(depth, 0.0f, 0.0f, 0.0f));
    566 }
    567 
    568 void clearStencil (const PixelBufferAccess& access, int stencil)
    569 {
    570 	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::S);
    571 
    572 	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_STENCIL), tcu::UVec4(stencil, 0u, 0u, 0u));
    573 }
    574 
    575 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
    576 {
    577 	DE_ASSERT(access.getHeight() == 1);
    578 	for (int x = 0; x < access.getWidth(); x++)
    579 	{
    580 		float s = ((float)x + 0.5f) / (float)access.getWidth();
    581 
    582 		float r = linearInterpolate(s, minVal.x(), maxVal.x());
    583 		float g = linearInterpolate(s, minVal.y(), maxVal.y());
    584 		float b = linearInterpolate(s, minVal.z(), maxVal.z());
    585 		float a = linearInterpolate(s, minVal.w(), maxVal.w());
    586 
    587 		access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
    588 	}
    589 }
    590 
    591 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
    592 {
    593 	for (int y = 0; y < access.getHeight(); y++)
    594 	{
    595 		for (int x = 0; x < access.getWidth(); x++)
    596 		{
    597 			float s = ((float)x + 0.5f) / (float)access.getWidth();
    598 			float t = ((float)y + 0.5f) / (float)access.getHeight();
    599 
    600 			float r = linearInterpolate((      s  +       t) *0.5f, minVal.x(), maxVal.x());
    601 			float g = linearInterpolate((      s  + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
    602 			float b = linearInterpolate(((1.0f-s) +       t) *0.5f, minVal.z(), maxVal.z());
    603 			float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
    604 
    605 			access.setPixel(tcu::Vec4(r, g, b, a), x, y);
    606 		}
    607 	}
    608 }
    609 
    610 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal)
    611 {
    612 	for (int z = 0; z < dst.getDepth(); z++)
    613 	{
    614 		for (int y = 0; y < dst.getHeight(); y++)
    615 		{
    616 			for (int x = 0; x < dst.getWidth(); x++)
    617 			{
    618 				float s = ((float)x + 0.5f) / (float)dst.getWidth();
    619 				float t = ((float)y + 0.5f) / (float)dst.getHeight();
    620 				float p = ((float)z + 0.5f) / (float)dst.getDepth();
    621 
    622 				float r = linearInterpolate(s,						minVal.x(), maxVal.x());
    623 				float g = linearInterpolate(t,						minVal.y(), maxVal.y());
    624 				float b = linearInterpolate(p,						minVal.z(), maxVal.z());
    625 				float a = linearInterpolate(1.0f - (s+t+p)/3.0f,	minVal.w(), maxVal.w());
    626 
    627 				dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
    628 			}
    629 		}
    630 	}
    631 }
    632 
    633 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
    634 {
    635 	if (isCombinedDepthStencilType(access.getFormat().type))
    636 	{
    637 		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
    638 		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
    639 
    640 		DE_ASSERT(hasDepth || hasStencil);
    641 
    642 		// For combined formats, treat D and S as separate channels
    643 		if (hasDepth)
    644 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal);
    645 		if (hasStencil)
    646 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0));
    647 	}
    648 	else
    649 	{
    650 		if (access.getHeight() == 1 && access.getDepth() == 1)
    651 			fillWithComponentGradients1D(access, minVal, maxVal);
    652 		else if (access.getDepth() == 1)
    653 			fillWithComponentGradients2D(access, minVal, maxVal);
    654 		else
    655 			fillWithComponentGradients3D(access, minVal, maxVal);
    656 	}
    657 }
    658 
    659 static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    660 {
    661 	for (int x = 0; x < access.getWidth(); x++)
    662 	{
    663 		int mx = (x / cellSize) % 2;
    664 
    665 		if (mx)
    666 			access.setPixel(colorB, x, 0);
    667 		else
    668 			access.setPixel(colorA, x, 0);
    669 	}
    670 }
    671 
    672 static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    673 {
    674 	for (int y = 0; y < access.getHeight(); y++)
    675 	{
    676 		for (int x = 0; x < access.getWidth(); x++)
    677 		{
    678 			int mx = (x / cellSize) % 2;
    679 			int my = (y / cellSize) % 2;
    680 
    681 			if (mx ^ my)
    682 				access.setPixel(colorB, x, y);
    683 			else
    684 				access.setPixel(colorA, x, y);
    685 		}
    686 	}
    687 }
    688 
    689 static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    690 {
    691 	for (int z = 0; z < access.getDepth(); z++)
    692 	{
    693 		for (int y = 0; y < access.getHeight(); y++)
    694 		{
    695 			for (int x = 0; x < access.getWidth(); x++)
    696 			{
    697 				int mx = (x / cellSize) % 2;
    698 				int my = (y / cellSize) % 2;
    699 				int mz = (z / cellSize) % 2;
    700 
    701 				if (mx ^ my ^ mz)
    702 					access.setPixel(colorB, x, y, z);
    703 				else
    704 					access.setPixel(colorA, x, y, z);
    705 			}
    706 		}
    707 	}
    708 }
    709 
    710 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    711 {
    712 	if (isCombinedDepthStencilType(access.getFormat().type))
    713 	{
    714 		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
    715 		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
    716 
    717 		DE_ASSERT(hasDepth || hasStencil);
    718 
    719 		// For combined formats, treat D and S as separate channels
    720 		if (hasDepth)
    721 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), colorA, colorB);
    722 		if (hasStencil)
    723 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0));
    724 	}
    725 	else
    726 	{
    727 		if (access.getHeight() == 1 && access.getDepth() == 1)
    728 			fillWithGrid1D(access, cellSize, colorA, colorB);
    729 		else if (access.getDepth() == 1)
    730 			fillWithGrid2D(access, cellSize, colorA, colorB);
    731 		else
    732 			fillWithGrid3D(access, cellSize, colorA, colorB);
    733 	}
    734 }
    735 
    736 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
    737 {
    738 	for (int y = 0; y < access.getHeight(); y++)
    739 	{
    740 		for (int x = 0; x < access.getWidth(); x++)
    741 		{
    742 			float s = ((float)x + 0.5f) / (float)access.getWidth();
    743 			float t = ((float)y + 0.5f) / (float)access.getHeight();
    744 
    745 			float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
    746 			float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
    747 
    748 			float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
    749 			access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
    750 		}
    751 	}
    752 }
    753 
    754 void fillWithRGBAQuads (const PixelBufferAccess& dst)
    755 {
    756 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
    757 	int width	= dst.getWidth();
    758 	int height	= dst.getHeight();
    759 	int	left	= width/2;
    760 	int top		= height/2;
    761 
    762 	clear(getSubregion(dst, 0,		0,		0, left,		top,		1),	Vec4(1.0f, 0.0f, 0.0f, 1.0f));
    763 	clear(getSubregion(dst, left,	0,		0, width-left,	top,		1),	Vec4(0.0f, 1.0f, 0.0f, 1.0f));
    764 	clear(getSubregion(dst, 0,		top,	0, left,		height-top,	1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
    765 	clear(getSubregion(dst, left,	top,	0, width-left,	height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
    766 }
    767 
    768 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
    769 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
    770 {
    771 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
    772 	std::vector<Vec2>	points(numBalls);
    773 	de::Random			rnd(seed);
    774 
    775 	for (int i = 0; i < numBalls; i++)
    776 	{
    777 		float x = rnd.getFloat();
    778 		float y = rnd.getFloat();
    779 		points[i] = (Vec2(x, y));
    780 	}
    781 
    782 	for (int y = 0; y < dst.getHeight(); y++)
    783 	for (int x = 0; x < dst.getWidth(); x++)
    784 	{
    785 		Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
    786 
    787 		float sum = 0.0f;
    788 		for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
    789 		{
    790 			Vec2	d = p - *i;
    791 			float	f = 0.01f / (d.x()*d.x() + d.y()*d.y());
    792 
    793 			sum += f;
    794 		}
    795 
    796 		dst.setPixel(Vec4(sum), x, y);
    797 	}
    798 }
    799 
    800 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src)
    801 {
    802 	DE_ASSERT(src.getSize() == dst.getSize());
    803 
    804 	const int	width				= dst.getWidth();
    805 	const int	height				= dst.getHeight();
    806 	const int	depth				= dst.getDepth();
    807 
    808 	const int	srcPixelSize		= src.getFormat().getPixelSize();
    809 	const int	dstPixelSize		= dst.getFormat().getPixelSize();
    810 	const int	srcPixelPitch		= src.getPixelPitch();
    811 	const int	dstPixelPitch		= dst.getPixelPitch();
    812 	const bool	srcTightlyPacked	= (srcPixelSize == srcPixelPitch);
    813 	const bool	dstTightlyPacked	= (dstPixelSize == dstPixelPitch);
    814 
    815 	const bool	srcHasDepth			= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D);
    816 	const bool	srcHasStencil		= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S);
    817 	const bool	dstHasDepth			= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D);
    818 	const bool	dstHasStencil		= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S);
    819 
    820 	if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked)
    821 	{
    822 		// Fast-path for matching formats.
    823 		for (int z = 0; z < depth; z++)
    824 		for (int y = 0; y < height; y++)
    825 			deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width);
    826 	}
    827 	else if (src.getFormat() == dst.getFormat())
    828 	{
    829 		// Bit-exact copy for matching formats.
    830 		for (int z = 0; z < depth; z++)
    831 		for (int y = 0; y < height; y++)
    832 		for (int x = 0; x < width; x++)
    833 			deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize);
    834 	}
    835 	else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil)
    836 	{
    837 		DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel
    838 
    839 		if (dstHasDepth && srcHasDepth)
    840 		{
    841 			for (int z = 0; z < depth; z++)
    842 			for (int y = 0; y < height; y++)
    843 			for (int x = 0; x < width; x++)
    844 				dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z);
    845 		}
    846 		else if (dstHasDepth && !srcHasDepth)
    847 		{
    848 			// consistency with color copies
    849 			tcu::clearDepth(dst, 0.0f);
    850 		}
    851 
    852 		if (dstHasStencil && srcHasStencil)
    853 		{
    854 			for (int z = 0; z < depth; z++)
    855 			for (int y = 0; y < height; y++)
    856 			for (int x = 0; x < width; x++)
    857 				dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
    858 		}
    859 		else if (dstHasStencil && !srcHasStencil)
    860 		{
    861 			// consistency with color copies
    862 			tcu::clearStencil(dst, 0u);
    863 		}
    864 	}
    865 	else
    866 	{
    867 		TextureChannelClass		srcClass	= getTextureChannelClass(src.getFormat().type);
    868 		TextureChannelClass		dstClass	= getTextureChannelClass(dst.getFormat().type);
    869 		bool					srcIsInt	= srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    870 		bool					dstIsInt	= dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    871 
    872 		if (srcIsInt && dstIsInt)
    873 		{
    874 			for (int z = 0; z < depth; z++)
    875 			for (int y = 0; y < height; y++)
    876 			for (int x = 0; x < width; x++)
    877 				dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
    878 		}
    879 		else
    880 		{
    881 			for (int z = 0; z < depth; z++)
    882 			for (int y = 0; y < height; y++)
    883 			for (int x = 0; x < width; x++)
    884 				dst.setPixel(src.getPixel(x, y, z), x, y, z);
    885 		}
    886 	}
    887 }
    888 
    889 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
    890 {
    891 	DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
    892 
    893 	Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
    894 					filter, filter, 0.0f, false);
    895 
    896 	float sX = (float)src.getWidth() / (float)dst.getWidth();
    897 	float sY = (float)src.getHeight() / (float)dst.getHeight();
    898 	float sZ = (float)src.getDepth() / (float)dst.getDepth();
    899 
    900 	if (dst.getDepth() == 1 && src.getDepth() == 1)
    901 	{
    902 		for (int y = 0; y < dst.getHeight(); y++)
    903 		for (int x = 0; x < dst.getWidth(); x++)
    904 			dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y);
    905 	}
    906 	else
    907 	{
    908 		for (int z = 0; z < dst.getDepth(); z++)
    909 		for (int y = 0; y < dst.getHeight(); y++)
    910 		for (int x = 0; x < dst.getWidth(); x++)
    911 			dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z);
    912 	}
    913 }
    914 
    915 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
    916 {
    917 	const TextureFormat& format = access.getFormat();
    918 
    919 	switch (getTextureChannelClass(format.type))
    920 	{
    921 		case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
    922 			// Normalized unsigned formats.
    923 			minVal = Vec4(0.0f);
    924 			maxVal = Vec4(1.0f);
    925 			break;
    926 
    927 		case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
    928 			// Normalized signed formats.
    929 			minVal = Vec4(-1.0f);
    930 			maxVal = Vec4(+1.0f);
    931 			break;
    932 
    933 		default:
    934 			// \note Samples every 4/8th pixel.
    935 			minVal = Vec4(std::numeric_limits<float>::max());
    936 			maxVal = Vec4(std::numeric_limits<float>::min());
    937 
    938 			for (int z = 0; z < access.getDepth(); z += 2)
    939 			{
    940 				for (int y = 0; y < access.getHeight(); y += 2)
    941 				{
    942 					for (int x = 0; x < access.getWidth(); x += 2)
    943 					{
    944 						Vec4 p = access.getPixel(x, y, z);
    945 
    946 						minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0]));
    947 						minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1]));
    948 						minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2]));
    949 						minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3]));
    950 
    951 						maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0]));
    952 						maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1]));
    953 						maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2]));
    954 						maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3]));
    955 					}
    956 				}
    957 			}
    958 			break;
    959 	}
    960 }
    961 
    962 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
    963 {
    964 	Vec4 minVal, maxVal;
    965 	estimatePixelValueRange(access, minVal, maxVal);
    966 
    967 	const float eps = 0.0001f;
    968 
    969 	for (int c = 0; c < 4; c++)
    970 	{
    971 		if (maxVal[c] - minVal[c] < eps)
    972 		{
    973 			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
    974 			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
    975 		}
    976 		else
    977 		{
    978 			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
    979 			bias[c]		= 0.0f - minVal[c]*scale[c];
    980 		}
    981 	}
    982 }
    983 
    984 int getCubeArrayFaceIndex (CubeFace face)
    985 {
    986 	DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
    987 
    988 	switch (face)
    989 	{
    990 		case CUBEFACE_POSITIVE_X:	return 0;
    991 		case CUBEFACE_NEGATIVE_X:	return 1;
    992 		case CUBEFACE_POSITIVE_Y:	return 2;
    993 		case CUBEFACE_NEGATIVE_Y:	return 3;
    994 		case CUBEFACE_POSITIVE_Z:	return 4;
    995 		case CUBEFACE_NEGATIVE_Z:	return 5;
    996 
    997 		default:
    998 			return -1;
    999 	}
   1000 }
   1001 
   1002 deUint32 packRGB999E5 (const tcu::Vec4& color)
   1003 {
   1004 	const int	mBits	= 9;
   1005 	const int	eBits	= 5;
   1006 	const int	eBias	= 15;
   1007 	const int	eMax	= (1<<eBits)-1;
   1008 	const float	maxVal	= (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits);
   1009 
   1010 	float	rc		= deFloatClamp(color[0], 0.0f, maxVal);
   1011 	float	gc		= deFloatClamp(color[1], 0.0f, maxVal);
   1012 	float	bc		= deFloatClamp(color[2], 0.0f, maxVal);
   1013 	float	maxc	= de::max(rc, de::max(gc, bc));
   1014 	int		expp	= de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias;
   1015 	float	e		= deFloatPow(2.0f, (float)(expp-eBias-mBits));
   1016 	int		maxs	= deFloorFloatToInt32(maxc / e + 0.5f);
   1017 
   1018 	deUint32	exps	= maxs == (1<<mBits) ? expp+1 : expp;
   1019 	deUint32	rs		= (deUint32)deClamp32(deFloorFloatToInt32(rc / e + 0.5f), 0, (1<<9)-1);
   1020 	deUint32	gs		= (deUint32)deClamp32(deFloorFloatToInt32(gc / e + 0.5f), 0, (1<<9)-1);
   1021 	deUint32	bs		= (deUint32)deClamp32(deFloorFloatToInt32(bc / e + 0.5f), 0, (1<<9)-1);
   1022 
   1023 	DE_ASSERT((exps & ~((1<<5)-1)) == 0);
   1024 	DE_ASSERT((rs & ~((1<<9)-1)) == 0);
   1025 	DE_ASSERT((gs & ~((1<<9)-1)) == 0);
   1026 	DE_ASSERT((bs & ~((1<<9)-1)) == 0);
   1027 
   1028 	return rs | (gs << 9) | (bs << 18) | (exps << 27);
   1029 }
   1030 
   1031 // Sampler utils
   1032 
   1033 static const void* addOffset (const void* ptr, int numBytes)
   1034 {
   1035 	return (const deUint8*)ptr + numBytes;
   1036 }
   1037 
   1038 static void* addOffset (void* ptr, int numBytes)
   1039 {
   1040 	return (deUint8*)ptr + numBytes;
   1041 }
   1042 
   1043 template <typename AccessType>
   1044 static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode)
   1045 {
   1046 	// make sure to update this if type table is updated
   1047 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
   1048 
   1049 	if (!isCombinedDepthStencilType(baseAccess.getFormat().type))
   1050 		return baseAccess;
   1051 	else
   1052 	{
   1053 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
   1054 		const deUint32 uint32ByteOffsetBits0To8	= 0; //!< least significant byte in the lowest address
   1055 		const deUint32 uint32ByteOffset8To32	= 1;
   1056 #else
   1057 		const deUint32 uint32ByteOffsetBits0To8	= 3; //!< least significant byte in the highest address
   1058 		const deUint32 uint32ByteOffset8To32	= 0;
   1059 #endif
   1060 
   1061 		// Sampled channel must exist
   1062 		DE_ASSERT(baseAccess.getFormat().order == TextureFormat::DS ||
   1063 				  (mode == Sampler::MODE_DEPTH && baseAccess.getFormat().order == TextureFormat::D) ||
   1064 				  (mode == Sampler::MODE_STENCIL && baseAccess.getFormat().order == TextureFormat::S));
   1065 
   1066 		// combined formats have multiple channel classes, detect on sampler settings
   1067 		switch (baseAccess.getFormat().type)
   1068 		{
   1069 			case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
   1070 			{
   1071 				if (mode == Sampler::MODE_DEPTH)
   1072 				{
   1073 					// select the float component
   1074 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::FLOAT),
   1075 									  baseAccess.getSize(),
   1076 									  baseAccess.getPitch(),
   1077 									  baseAccess.getDataPtr());
   1078 				}
   1079 				else if (mode == Sampler::MODE_STENCIL)
   1080 				{
   1081 					// select the uint 8 component
   1082 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
   1083 									  baseAccess.getSize(),
   1084 									  baseAccess.getPitch(),
   1085 									  addOffset(baseAccess.getDataPtr(), 4 + uint32ByteOffsetBits0To8));
   1086 				}
   1087 				else
   1088 				{
   1089 					// unknown sampler mode
   1090 					DE_ASSERT(false);
   1091 					return AccessType();
   1092 				}
   1093 			}
   1094 
   1095 			case TextureFormat::UNSIGNED_INT_24_8:
   1096 			{
   1097 				if (mode == Sampler::MODE_DEPTH)
   1098 				{
   1099 					// select the unorm24 component
   1100 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
   1101 									  baseAccess.getSize(),
   1102 									  baseAccess.getPitch(),
   1103 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffset8To32));
   1104 				}
   1105 				else if (mode == Sampler::MODE_STENCIL)
   1106 				{
   1107 					// select the uint 8 component
   1108 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
   1109 									  baseAccess.getSize(),
   1110 									  baseAccess.getPitch(),
   1111 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
   1112 				}
   1113 				else
   1114 				{
   1115 					// unknown sampler mode
   1116 					DE_ASSERT(false);
   1117 					return AccessType();
   1118 				}
   1119 			}
   1120 
   1121 			default:
   1122 			{
   1123 				// unknown combined format
   1124 				DE_ASSERT(false);
   1125 				return AccessType();
   1126 			}
   1127 		}
   1128 	}
   1129 }
   1130 
   1131 PixelBufferAccess getEffectiveDepthStencilAccess (const PixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
   1132 {
   1133 	return toSamplerAccess<PixelBufferAccess>(baseAccess, mode);
   1134 }
   1135 
   1136 ConstPixelBufferAccess getEffectiveDepthStencilAccess (const ConstPixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
   1137 {
   1138 	return toSamplerAccess<ConstPixelBufferAccess>(baseAccess, mode);
   1139 }
   1140 
   1141 TextureFormat getEffectiveDepthStencilTextureFormat (const TextureFormat& baseFormat, Sampler::DepthStencilMode mode)
   1142 {
   1143 	return toSamplerAccess(ConstPixelBufferAccess(baseFormat, IVec3(0, 0, 0), DE_NULL), mode).getFormat();
   1144 }
   1145 
   1146 template <typename ViewType>
   1147 ViewType getEffectiveTView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1148 {
   1149 	storage.resize(src.getNumLevels());
   1150 
   1151 	ViewType view = ViewType(src.getNumLevels(), &storage[0]);
   1152 
   1153 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
   1154 		storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode);
   1155 
   1156 	return view;
   1157 }
   1158 
   1159 tcu::TextureCubeView getEffectiveTView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1160 {
   1161 	storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels());
   1162 
   1163 	const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] =
   1164 	{
   1165 		&storage[0 * src.getNumLevels()],
   1166 		&storage[1 * src.getNumLevels()],
   1167 		&storage[2 * src.getNumLevels()],
   1168 		&storage[3 * src.getNumLevels()],
   1169 		&storage[4 * src.getNumLevels()],
   1170 		&storage[5 * src.getNumLevels()],
   1171 	};
   1172 
   1173 	tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs);
   1174 
   1175 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
   1176 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
   1177 		storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode);
   1178 
   1179 	return view;
   1180 }
   1181 
   1182 tcu::Texture1DView getEffectiveTextureView (const tcu::Texture1DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1183 {
   1184 	return getEffectiveTView(src, storage, sampler);
   1185 }
   1186 
   1187 tcu::Texture2DView getEffectiveTextureView (const tcu::Texture2DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1188 {
   1189 	return getEffectiveTView(src, storage, sampler);
   1190 }
   1191 
   1192 tcu::Texture3DView getEffectiveTextureView (const tcu::Texture3DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1193 {
   1194 	return getEffectiveTView(src, storage, sampler);
   1195 }
   1196 
   1197 tcu::Texture1DArrayView getEffectiveTextureView (const tcu::Texture1DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1198 {
   1199 	return getEffectiveTView(src, storage, sampler);
   1200 }
   1201 
   1202 tcu::Texture2DArrayView getEffectiveTextureView (const tcu::Texture2DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1203 {
   1204 	return getEffectiveTView(src, storage, sampler);
   1205 }
   1206 
   1207 tcu::TextureCubeView getEffectiveTextureView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1208 {
   1209 	return getEffectiveTView(src, storage, sampler);
   1210 }
   1211 
   1212 tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
   1213 {
   1214 	return getEffectiveTView(src, storage, sampler);
   1215 }
   1216 
   1217 //! Returns the effective swizzle of a border color. The effective swizzle is the
   1218 //! equal to first writing an RGBA color with a write swizzle and then reading
   1219 //! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
   1220 static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order)
   1221 {
   1222 	// make sure to update these tables when channel orders are updated
   1223 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 18);
   1224 
   1225 	static const TextureSwizzle INV		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
   1226 	static const TextureSwizzle R		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
   1227 	static const TextureSwizzle A		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
   1228 	static const TextureSwizzle I		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0	}};
   1229 	static const TextureSwizzle L		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ONE	}};
   1230 	static const TextureSwizzle LA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3	}};
   1231 	static const TextureSwizzle RG		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
   1232 	static const TextureSwizzle RA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
   1233 	static const TextureSwizzle RGB		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_ONE	}};
   1234 	static const TextureSwizzle RGBA	= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3	}};
   1235 	static const TextureSwizzle D		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
   1236 	static const TextureSwizzle S		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
   1237 
   1238 	const TextureSwizzle* swizzle;
   1239 
   1240 	switch (order)
   1241 	{
   1242 		case TextureFormat::R:			swizzle = &R;		break;
   1243 		case TextureFormat::A:			swizzle = &A;		break;
   1244 		case TextureFormat::I:			swizzle = &I;		break;
   1245 		case TextureFormat::L:			swizzle = &L;		break;
   1246 		case TextureFormat::LA:			swizzle = &LA;		break;
   1247 		case TextureFormat::RG:			swizzle = &RG;		break;
   1248 		case TextureFormat::RA:			swizzle = &RA;		break;
   1249 		case TextureFormat::RGB:		swizzle = &RGB;		break;
   1250 		case TextureFormat::RGBA:		swizzle = &RGBA;	break;
   1251 		case TextureFormat::ARGB:		swizzle = &RGBA;	break;
   1252 		case TextureFormat::BGRA:		swizzle = &RGBA;	break;
   1253 		case TextureFormat::sR:			swizzle = &R;		break;
   1254 		case TextureFormat::sRG:		swizzle = &RG;		break;
   1255 		case TextureFormat::sRGB:		swizzle = &RGB;		break;
   1256 		case TextureFormat::sRGBA:		swizzle = &RGBA;	break;
   1257 		case TextureFormat::D:			swizzle = &D;		break;
   1258 		case TextureFormat::S:			swizzle = &S;		break;
   1259 
   1260 		case TextureFormat::DS:
   1261 			DE_ASSERT(false); // combined depth-stencil border color?
   1262 			swizzle = &INV;
   1263 			break;
   1264 
   1265 		default:
   1266 			DE_ASSERT(false);
   1267 			swizzle = &INV;
   1268 			break;
   1269 	}
   1270 
   1271 #ifdef DE_DEBUG
   1272 
   1273 	{
   1274 		// check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
   1275 		const TextureSwizzle& readSwizzle	= getChannelReadSwizzle(order);
   1276 		const TextureSwizzle& writeSwizzle	= getChannelWriteSwizzle(order);
   1277 
   1278 		for (int ndx = 0; ndx < 4; ++ndx)
   1279 		{
   1280 			TextureSwizzle::Channel writeRead = readSwizzle.components[ndx];
   1281 			if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE)
   1282 				writeRead = writeSwizzle.components[(int)writeRead];
   1283 			DE_ASSERT(writeRead == swizzle->components[ndx]);
   1284 		}
   1285 	}
   1286 
   1287 #endif
   1288 
   1289 	return *swizzle;
   1290 }
   1291 
   1292 static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
   1293 {
   1294 	return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0),
   1295 					  (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0),
   1296 					  (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0),
   1297 					  (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0));
   1298 }
   1299 
   1300 static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
   1301 {
   1302 	return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0),
   1303 					  (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0),
   1304 					  (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0),
   1305 					  (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0));
   1306 }
   1307 
   1308 static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits)
   1309 {
   1310 	return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0),
   1311 					  (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0),
   1312 					  (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0),
   1313 					  (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0));
   1314 }
   1315 
   1316 static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler)
   1317 {
   1318 	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
   1319 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
   1320 	const bool						isFloat			= channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
   1321 	const bool						isSigned		= channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
   1322 	const float						valueMin		= (isSigned) ? (-1.0f) : (0.0f);
   1323 	const float						valueMax		= 1.0f;
   1324 	Vec4							result;
   1325 
   1326 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
   1327 			  channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
   1328 			  channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
   1329 
   1330 	for (int c = 0; c < 4; c++)
   1331 	{
   1332 		const TextureSwizzle::Channel map = channelMap[c];
   1333 		if (map == TextureSwizzle::CHANNEL_ZERO)
   1334 			result[c] = 0.0f;
   1335 		else if (map == TextureSwizzle::CHANNEL_ONE)
   1336 			result[c] = 1.0f;
   1337 		else if (isFloat)
   1338 		{
   1339 			// floating point values are not clamped
   1340 			result[c] = sampler.borderColor.getAccess<float>()[(int)map];
   1341 		}
   1342 		else
   1343 		{
   1344 			// fixed point values are clamped to a representable range
   1345 			result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax);
   1346 		}
   1347 	}
   1348 
   1349 	return result;
   1350 }
   1351 
   1352 static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler)
   1353 {
   1354 	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
   1355 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
   1356 	const IVec4						channelBits		= getChannelBitDepth(format.type);
   1357 	const IVec4						valueMin		= getNBitSignedIntegerVec4MinValue(channelBits);
   1358 	const IVec4						valueMax		= getNBitSignedIntegerVec4MaxValue(channelBits);
   1359 	IVec4							result;
   1360 
   1361 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
   1362 	DE_UNREF(channelClass);
   1363 
   1364 	for (int c = 0; c < 4; c++)
   1365 	{
   1366 		const TextureSwizzle::Channel map = channelMap[c];
   1367 		if (map == TextureSwizzle::CHANNEL_ZERO)
   1368 			result[c] = 0;
   1369 		else if (map == TextureSwizzle::CHANNEL_ONE)
   1370 			result[c] = 1;
   1371 		else
   1372 		{
   1373 			// integer values are clamped to a representable range
   1374 			result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]);
   1375 		}
   1376 	}
   1377 
   1378 	return result;
   1379 }
   1380 
   1381 static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler)
   1382 {
   1383 	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
   1384 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
   1385 	const IVec4						channelBits		= getChannelBitDepth(format.type);
   1386 	const UVec4						valueMax		= getNBitUnsignedIntegerVec4MaxValue(channelBits);
   1387 	UVec4							result;
   1388 
   1389 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
   1390 	DE_UNREF(channelClass);
   1391 
   1392 	for (int c = 0; c < 4; c++)
   1393 	{
   1394 		const TextureSwizzle::Channel map = channelMap[c];
   1395 		if (map == TextureSwizzle::CHANNEL_ZERO)
   1396 			result[c] = 0;
   1397 		else if (map == TextureSwizzle::CHANNEL_ONE)
   1398 			result[c] = 1;
   1399 		else
   1400 		{
   1401 			// integer values are clamped to a representable range
   1402 			result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]);
   1403 		}
   1404 	}
   1405 
   1406 	return result;
   1407 }
   1408 
   1409 template <typename ScalarType>
   1410 tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler)
   1411 {
   1412 	const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
   1413 
   1414 	switch (channelClass)
   1415 	{
   1416 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
   1417 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
   1418 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
   1419 			return getTextureBorderColorFloat(format, sampler).cast<ScalarType>();
   1420 
   1421 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
   1422 			return getTextureBorderColorInt(format, sampler).cast<ScalarType>();
   1423 
   1424 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
   1425 			return getTextureBorderColorUint(format, sampler).cast<ScalarType>();
   1426 
   1427 		default:
   1428 			DE_ASSERT(false);
   1429 			return tcu::Vector<ScalarType, 4>();
   1430 	}
   1431 }
   1432 
   1433 // instantiation
   1434 template tcu::Vector<float, 4>		sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
   1435 template tcu::Vector<deInt32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
   1436 template tcu::Vector<deUint32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
   1437 
   1438 } // tcu
   1439