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 Reference Texture Implementation.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuTexture.hpp"
     25 #include "deInt32.h"
     26 #include "deFloat16.h"
     27 #include "deMath.h"
     28 #include "deMemory.h"
     29 #include "tcuTestLog.hpp"
     30 #include "tcuSurface.hpp"
     31 #include "tcuFloat.hpp"
     32 #include "tcuTextureUtil.hpp"
     33 #include "deStringUtil.hpp"
     34 
     35 #include <limits>
     36 
     37 namespace tcu
     38 {
     39 
     40 // \note No denorm support, no sign.
     41 typedef Float<deUint32, 5, 6, 15, 0>	Float11;
     42 typedef Float<deUint32, 5, 5, 15, 0>	Float10;
     43 
     44 namespace
     45 {
     46 
     47 // Optimized getters for common formats.
     48 // \todo [2012-11-14 pyry] Use intrinsics if available.
     49 
     50 inline Vec4		readRGBA8888Float	(const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, ptr[3]/255.0f); }
     51 inline Vec4		readRGB888Float		(const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, 1.0f); }
     52 inline IVec4	readRGBA8888Int		(const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], ptr[3]); }
     53 inline IVec4	readRGB888Int		(const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], 0xff); }
     54 
     55 // Optimized setters.
     56 
     57 inline void writeRGBA8888Int (deUint8* ptr, const IVec4& val)
     58 {
     59 	ptr[0] = de::clamp(val[0], 0, 255);
     60 	ptr[1] = de::clamp(val[1], 0, 255);
     61 	ptr[2] = de::clamp(val[2], 0, 255);
     62 	ptr[3] = de::clamp(val[3], 0, 255);
     63 }
     64 
     65 inline void writeRGB888Int (deUint8* ptr, const IVec4& val)
     66 {
     67 	ptr[0] = de::clamp(val[0], 0, 255);
     68 	ptr[1] = de::clamp(val[1], 0, 255);
     69 	ptr[2] = de::clamp(val[2], 0, 255);
     70 }
     71 
     72 inline void writeRGBA8888Float (deUint8* ptr, const Vec4& val)
     73 {
     74 	ptr[0] = floatToU8(val[0]);
     75 	ptr[1] = floatToU8(val[1]);
     76 	ptr[2] = floatToU8(val[2]);
     77 	ptr[3] = floatToU8(val[3]);
     78 }
     79 
     80 inline void writeRGB888Float (deUint8* ptr, const Vec4& val)
     81 {
     82 	ptr[0] = floatToU8(val[0]);
     83 	ptr[1] = floatToU8(val[1]);
     84 	ptr[2] = floatToU8(val[2]);
     85 }
     86 
     87 enum Channel
     88 {
     89 	// \note CHANNEL_N must equal int N
     90 	CHANNEL_0 = 0,
     91 	CHANNEL_1,
     92 	CHANNEL_2,
     93 	CHANNEL_3,
     94 
     95 	CHANNEL_ZERO,
     96 	CHANNEL_ONE
     97 };
     98 
     99 // \todo [2011-09-21 pyry] Move to tcutil?
    100 template <typename T>
    101 inline T convertSatRte (float f)
    102 {
    103 	// \note Doesn't work for 64-bit types
    104 	DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
    105 	DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
    106 
    107 	deInt64	minVal	= std::numeric_limits<T>::min();
    108 	deInt64 maxVal	= std::numeric_limits<T>::max();
    109 	float	q		= deFloatFrac(f);
    110 	deInt64 intVal	= (deInt64)(f-q);
    111 
    112 	// Rounding.
    113 	if (q == 0.5f)
    114 	{
    115 		if (intVal % 2 != 0)
    116 			intVal++;
    117 	}
    118 	else if (q > 0.5f)
    119 		intVal++;
    120 	// else Don't add anything
    121 
    122 	// Saturate.
    123 	intVal = de::max(minVal, de::min(maxVal, intVal));
    124 
    125 	return (T)intVal;
    126 }
    127 
    128 const Channel* getChannelReadMap (TextureFormat::ChannelOrder order)
    129 {
    130 	static const Channel INV[]	= { CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_ONE };
    131 	static const Channel R[]	= { CHANNEL_0,		CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_ONE };
    132 	static const Channel A[]	= { CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_0	};
    133 	static const Channel I[]	= { CHANNEL_0,		CHANNEL_0,		CHANNEL_0,		CHANNEL_0	};
    134 	static const Channel L[]	= { CHANNEL_0,		CHANNEL_0,		CHANNEL_0,		CHANNEL_ONE	};
    135 	static const Channel LA[]	= { CHANNEL_0,		CHANNEL_0,		CHANNEL_0,		CHANNEL_1	};
    136 	static const Channel RG[]	= { CHANNEL_0,		CHANNEL_1,		CHANNEL_ZERO,	CHANNEL_ONE	};
    137 	static const Channel RA[]	= { CHANNEL_0,		CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_1	};
    138 	static const Channel RGB[]	= { CHANNEL_0,		CHANNEL_1,		CHANNEL_2,		CHANNEL_ONE	};
    139 	static const Channel RGBA[]	= { CHANNEL_0,		CHANNEL_1,		CHANNEL_2,		CHANNEL_3	};
    140 	static const Channel BGRA[]	= { CHANNEL_2,		CHANNEL_1,		CHANNEL_0,		CHANNEL_3	};
    141 	static const Channel ARGB[]	= { CHANNEL_1,		CHANNEL_2,		CHANNEL_3,		CHANNEL_0	};
    142 	static const Channel D[]	= { CHANNEL_0,		CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_ONE	};
    143 	static const Channel S[]	= { CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_0	};
    144 	static const Channel DS[]	= { CHANNEL_0,		CHANNEL_ZERO,	CHANNEL_ZERO,	CHANNEL_1	};
    145 
    146 	switch (order)
    147 	{
    148 		case TextureFormat::R:			return R;
    149 		case TextureFormat::A:			return A;
    150 		case TextureFormat::I:			return I;
    151 		case TextureFormat::L:			return L;
    152 		case TextureFormat::LA:			return LA;
    153 		case TextureFormat::RG:			return RG;
    154 		case TextureFormat::RA:			return RA;
    155 		case TextureFormat::RGB:		return RGB;
    156 		case TextureFormat::RGBA:		return RGBA;
    157 		case TextureFormat::ARGB:		return ARGB;
    158 		case TextureFormat::BGRA:		return BGRA;
    159 		case TextureFormat::sRGB:		return RGB;
    160 		case TextureFormat::sRGBA:		return RGBA;
    161 		case TextureFormat::D:			return D;
    162 		case TextureFormat::S:			return S;
    163 		case TextureFormat::DS:			return DS;
    164 		default:
    165 			DE_ASSERT(DE_FALSE);
    166 			return INV;
    167 	}
    168 }
    169 
    170 const int* getChannelWriteMap (TextureFormat::ChannelOrder order)
    171 {
    172 	static const int R[]	= { 0 };
    173 	static const int A[]	= { 3 };
    174 	static const int I[]	= { 0 };
    175 	static const int L[]	= { 0 };
    176 	static const int LA[]	= { 0, 3 };
    177 	static const int RG[]	= { 0, 1 };
    178 	static const int RA[]	= { 0, 3 };
    179 	static const int RGB[]	= { 0, 1, 2 };
    180 	static const int RGBA[]	= { 0, 1, 2, 3 };
    181 	static const int BGRA[]	= { 2, 1, 0, 3 };
    182 	static const int ARGB[]	= { 3, 0, 1, 2 };
    183 	static const int D[]	= { 0 };
    184 	static const int S[]	= { 3 };
    185 	static const int DS[]	= { 0, 3 };
    186 
    187 	switch (order)
    188 	{
    189 		case TextureFormat::R:			return R;
    190 		case TextureFormat::A:			return A;
    191 		case TextureFormat::I:			return I;
    192 		case TextureFormat::L:			return L;
    193 		case TextureFormat::LA:			return LA;
    194 		case TextureFormat::RG:			return RG;
    195 		case TextureFormat::RA:			return RA;
    196 		case TextureFormat::RGB:		return RGB;
    197 		case TextureFormat::RGBA:		return RGBA;
    198 		case TextureFormat::ARGB:		return ARGB;
    199 		case TextureFormat::BGRA:		return BGRA;
    200 		case TextureFormat::sRGB:		return RGB;
    201 		case TextureFormat::sRGBA:		return RGBA;
    202 		case TextureFormat::D:			return D;
    203 		case TextureFormat::S:			return S;
    204 		case TextureFormat::DS:			return DS;
    205 		default:
    206 			DE_ASSERT(DE_FALSE);
    207 			return DE_NULL;
    208 	}
    209 }
    210 
    211 int getChannelSize (TextureFormat::ChannelType type)
    212 {
    213 	switch (type)
    214 	{
    215 		case TextureFormat::SNORM_INT8:			return 1;
    216 		case TextureFormat::SNORM_INT16:		return 2;
    217 		case TextureFormat::SNORM_INT32:		return 4;
    218 		case TextureFormat::UNORM_INT8:			return 1;
    219 		case TextureFormat::UNORM_INT16:		return 2;
    220 		case TextureFormat::UNORM_INT32:		return 4;
    221 		case TextureFormat::SIGNED_INT8:		return 1;
    222 		case TextureFormat::SIGNED_INT16:		return 2;
    223 		case TextureFormat::SIGNED_INT32:		return 4;
    224 		case TextureFormat::UNSIGNED_INT8:		return 1;
    225 		case TextureFormat::UNSIGNED_INT16:		return 2;
    226 		case TextureFormat::UNSIGNED_INT32:		return 4;
    227 		case TextureFormat::HALF_FLOAT:			return 2;
    228 		case TextureFormat::FLOAT:				return 4;
    229 		default:
    230 			DE_ASSERT(DE_FALSE);
    231 			return 0;
    232 	}
    233 }
    234 
    235 int getNumUsedChannels (TextureFormat::ChannelOrder order)
    236 {
    237 	switch (order)
    238 	{
    239 		case TextureFormat::R:			return 1;
    240 		case TextureFormat::A:			return 1;
    241 		case TextureFormat::I:			return 1;
    242 		case TextureFormat::L:			return 1;
    243 		case TextureFormat::LA:			return 2;
    244 		case TextureFormat::RG:			return 2;
    245 		case TextureFormat::RA:			return 2;
    246 		case TextureFormat::RGB:		return 3;
    247 		case TextureFormat::RGBA:		return 4;
    248 		case TextureFormat::ARGB:		return 4;
    249 		case TextureFormat::BGRA:		return 4;
    250 		case TextureFormat::sRGB:		return 3;
    251 		case TextureFormat::sRGBA:		return 4;
    252 		case TextureFormat::D:			return 1;
    253 		case TextureFormat::S:			return 1;
    254 		case TextureFormat::DS:			return 2;
    255 		default:
    256 			DE_ASSERT(DE_FALSE);
    257 			return 0;
    258 	}
    259 }
    260 
    261 inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
    262 {
    263 	switch (type)
    264 	{
    265 		case TextureFormat::SNORM_INT8:			return de::max(-1.0f, (float)*((const deInt8*)value) / 127.0f);
    266 		case TextureFormat::SNORM_INT16:		return de::max(-1.0f, (float)*((const deInt16*)value) / 32767.0f);
    267 		case TextureFormat::SNORM_INT32:		return de::max(-1.0f, (float)*((const deInt32*)value) / 2147483647.0f);
    268 		case TextureFormat::UNORM_INT8:			return (float)*((const deUint8*)value) / 255.0f;
    269 		case TextureFormat::UNORM_INT16:		return (float)*((const deUint16*)value) / 65535.0f;
    270 		case TextureFormat::UNORM_INT32:		return (float)*((const deUint32*)value) / 4294967295.0f;
    271 		case TextureFormat::SIGNED_INT8:		return (float)*((const deInt8*)value);
    272 		case TextureFormat::SIGNED_INT16:		return (float)*((const deInt16*)value);
    273 		case TextureFormat::SIGNED_INT32:		return (float)*((const deInt32*)value);
    274 		case TextureFormat::UNSIGNED_INT8:		return (float)*((const deUint8*)value);
    275 		case TextureFormat::UNSIGNED_INT16:		return (float)*((const deUint16*)value);
    276 		case TextureFormat::UNSIGNED_INT32:		return (float)*((const deUint32*)value);
    277 		case TextureFormat::HALF_FLOAT:			return deFloat16To32(*(const deFloat16*)value);
    278 		case TextureFormat::FLOAT:				return *((const float*)value);
    279 		default:
    280 			DE_ASSERT(DE_FALSE);
    281 			return 0.0f;
    282 	}
    283 }
    284 
    285 inline int channelToInt (const deUint8* value, TextureFormat::ChannelType type)
    286 {
    287 	switch (type)
    288 	{
    289 		case TextureFormat::SNORM_INT8:			return (int)*((const deInt8*)value);
    290 		case TextureFormat::SNORM_INT16:		return (int)*((const deInt16*)value);
    291 		case TextureFormat::SNORM_INT32:		return (int)*((const deInt32*)value);
    292 		case TextureFormat::UNORM_INT8:			return (int)*((const deUint8*)value);
    293 		case TextureFormat::UNORM_INT16:		return (int)*((const deUint16*)value);
    294 		case TextureFormat::UNORM_INT32:		return (int)*((const deUint32*)value);
    295 		case TextureFormat::SIGNED_INT8:		return (int)*((const deInt8*)value);
    296 		case TextureFormat::SIGNED_INT16:		return (int)*((const deInt16*)value);
    297 		case TextureFormat::SIGNED_INT32:		return (int)*((const deInt32*)value);
    298 		case TextureFormat::UNSIGNED_INT8:		return (int)*((const deUint8*)value);
    299 		case TextureFormat::UNSIGNED_INT16:		return (int)*((const deUint16*)value);
    300 		case TextureFormat::UNSIGNED_INT32:		return (int)*((const deUint32*)value);
    301 		case TextureFormat::HALF_FLOAT:			return (int)deFloat16To32(*(const deFloat16*)value);
    302 		case TextureFormat::FLOAT:				return (int)*((const float*)value);
    303 		default:
    304 			DE_ASSERT(DE_FALSE);
    305 			return 0;
    306 	}
    307 }
    308 
    309 void floatToChannel (deUint8* dst, float src, TextureFormat::ChannelType type)
    310 {
    311 	switch (type)
    312 	{
    313 		case TextureFormat::SNORM_INT8:			*((deInt8*)dst)			= convertSatRte<deInt8>		(src * 127.0f);			break;
    314 		case TextureFormat::SNORM_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src * 32767.0f);		break;
    315 		case TextureFormat::SNORM_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src * 2147483647.0f);	break;
    316 		case TextureFormat::UNORM_INT8:			*((deUint8*)dst)		= convertSatRte<deUint8>	(src * 255.0f);			break;
    317 		case TextureFormat::UNORM_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src * 65535.0f);		break;
    318 		case TextureFormat::UNORM_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(src * 4294967295.0f);	break;
    319 		case TextureFormat::SIGNED_INT8:		*((deInt8*)dst)			= convertSatRte<deInt8>		(src);					break;
    320 		case TextureFormat::SIGNED_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src);					break;
    321 		case TextureFormat::SIGNED_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src);					break;
    322 		case TextureFormat::UNSIGNED_INT8:		*((deUint8*)dst)		= convertSatRte<deUint8>	(src);					break;
    323 		case TextureFormat::UNSIGNED_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src);					break;
    324 		case TextureFormat::UNSIGNED_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(src);					break;
    325 		case TextureFormat::HALF_FLOAT:			*((deFloat16*)dst)		= deFloat32To16				(src);					break;
    326 		case TextureFormat::FLOAT:				*((float*)dst)			= src;												break;
    327 		default:
    328 			DE_ASSERT(DE_FALSE);
    329 	}
    330 }
    331 
    332 template <typename T, typename S>
    333 static inline T convertSat (S src)
    334 {
    335 	S min = (S)std::numeric_limits<T>::min();
    336 	S max = (S)std::numeric_limits<T>::max();
    337 
    338 	if (src < min)
    339 		return (T)min;
    340 	else if (src > max)
    341 		return (T)max;
    342 	else
    343 		return (T)src;
    344 }
    345 
    346 void intToChannel (deUint8* dst, int src, TextureFormat::ChannelType type)
    347 {
    348 	switch (type)
    349 	{
    350 		case TextureFormat::SNORM_INT8:			*((deInt8*)dst)			= convertSat<deInt8>	(src);				break;
    351 		case TextureFormat::SNORM_INT16:		*((deInt16*)dst)		= convertSat<deInt16>	(src);				break;
    352 		case TextureFormat::UNORM_INT8:			*((deUint8*)dst)		= convertSat<deUint8>	(src);				break;
    353 		case TextureFormat::UNORM_INT16:		*((deUint16*)dst)		= convertSat<deUint16>	(src);				break;
    354 		case TextureFormat::SIGNED_INT8:		*((deInt8*)dst)			= convertSat<deInt8>	(src);				break;
    355 		case TextureFormat::SIGNED_INT16:		*((deInt16*)dst)		= convertSat<deInt16>	(src);				break;
    356 		case TextureFormat::SIGNED_INT32:		*((deInt32*)dst)		= convertSat<deInt32>	(src);				break;
    357 		case TextureFormat::UNSIGNED_INT8:		*((deUint8*)dst)		= convertSat<deUint8>	((deUint32)src);	break;
    358 		case TextureFormat::UNSIGNED_INT16:		*((deUint16*)dst)		= convertSat<deUint16>	((deUint32)src);	break;
    359 		case TextureFormat::UNSIGNED_INT32:		*((deUint32*)dst)		= convertSat<deUint32>	((deUint32)src);	break;
    360 		case TextureFormat::HALF_FLOAT:			*((deFloat16*)dst)		= deFloat32To16((float)src);				break;
    361 		case TextureFormat::FLOAT:				*((float*)dst)			= (float)src;								break;
    362 		default:
    363 			DE_ASSERT(DE_FALSE);
    364 	}
    365 }
    366 
    367 inline float channelToNormFloat (deUint32 src, int bits)
    368 {
    369 	deUint32 maxVal = (1u << bits) - 1;
    370 	return (float)src / (float)maxVal;
    371 }
    372 
    373 inline deUint32 normFloatToChannel (float src, int bits)
    374 {
    375 	deUint32 maxVal = (1u << bits) - 1;
    376 	deUint32 intVal = convertSatRte<deUint32>(src * (float)maxVal);
    377 	return de::min(maxVal, intVal);
    378 }
    379 
    380 inline deUint32 uintToChannel (deUint32 src, int bits)
    381 {
    382 	deUint32 maxVal = (1u << bits) - 1;
    383 	return de::min(maxVal, src);
    384 }
    385 
    386 deUint32 packRGB999E5 (const tcu::Vec4& color)
    387 {
    388 	const int	mBits	= 9;
    389 	const int	eBits	= 5;
    390 	const int	eBias	= 15;
    391 	const int	eMax	= (1<<eBits)-1;
    392 	const float	maxVal	= (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits);
    393 
    394 	float	rc		= deFloatClamp(color[0], 0.0f, maxVal);
    395 	float	gc		= deFloatClamp(color[1], 0.0f, maxVal);
    396 	float	bc		= deFloatClamp(color[2], 0.0f, maxVal);
    397 	float	maxc	= de::max(rc, de::max(gc, bc));
    398 	int		expp	= de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias;
    399 	float	e		= deFloatPow(2.0f, (float)(expp-eBias-mBits));
    400 	int		maxs	= deFloorFloatToInt32(maxc / e + 0.5f);
    401 
    402 	deUint32	exps	= maxs == (1<<mBits) ? expp+1 : expp;
    403 	deUint32	rs		= (deUint32)deClamp32(deFloorFloatToInt32(rc / e + 0.5f), 0, (1<<9)-1);
    404 	deUint32	gs		= (deUint32)deClamp32(deFloorFloatToInt32(gc / e + 0.5f), 0, (1<<9)-1);
    405 	deUint32	bs		= (deUint32)deClamp32(deFloorFloatToInt32(bc / e + 0.5f), 0, (1<<9)-1);
    406 
    407 	DE_ASSERT((exps & ~((1<<5)-1)) == 0);
    408 	DE_ASSERT((rs & ~((1<<9)-1)) == 0);
    409 	DE_ASSERT((gs & ~((1<<9)-1)) == 0);
    410 	DE_ASSERT((bs & ~((1<<9)-1)) == 0);
    411 
    412 	return rs | (gs << 9) | (bs << 18) | (exps << 27);
    413 }
    414 
    415 tcu::Vec4 unpackRGB999E5 (deUint32 color)
    416 {
    417 	const int	mBits	= 9;
    418 	const int	eBias	= 15;
    419 
    420 	deUint32	exp		= color >> 27;
    421 	deUint32	bs		= (color >> 18) & ((1<<9)-1);
    422 	deUint32	gs		= (color >> 9) & ((1<<9)-1);
    423 	deUint32	rs		= color & ((1<<9)-1);
    424 
    425 	float		e		= deFloatPow(2.0f, (float)((int)exp - eBias - mBits));
    426 	float		r		= (float)rs * e;
    427 	float		g		= (float)gs * e;
    428 	float		b		= (float)bs * e;
    429 
    430 	return tcu::Vec4(r, g, b, 1.0f);
    431 }
    432 
    433 } // anonymous
    434 
    435 /** Get pixel size in bytes. */
    436 int TextureFormat::getPixelSize (void) const
    437 {
    438 	if (type == CHANNELTYPE_LAST && order == CHANNELORDER_LAST)
    439 	{
    440 		// Invalid/empty format.
    441 		return 0;
    442 	}
    443 	else if (type == UNORM_SHORT_565	||
    444 			 type == UNORM_SHORT_555	||
    445 			 type == UNORM_SHORT_4444	||
    446 			 type == UNORM_SHORT_5551)
    447 	{
    448 		DE_ASSERT(order == RGB || order == RGBA);
    449 		return 2;
    450 	}
    451 	else if (type == UNORM_INT_101010			||
    452 			 type == UNSIGNED_INT_999_E5_REV	||
    453 			 type == UNSIGNED_INT_11F_11F_10F_REV)
    454 	{
    455 		DE_ASSERT(order == RGB);
    456 		return 4;
    457 	}
    458 	else if (type == UNORM_INT_1010102_REV		||
    459 			 type == UNSIGNED_INT_1010102_REV)
    460 	{
    461 		DE_ASSERT(order == RGBA);
    462 		return 4;
    463 	}
    464 	else if (type == UNSIGNED_INT_24_8)
    465 	{
    466 		DE_ASSERT(order == D || order == DS);
    467 		return 4;
    468 	}
    469 	else if (type == FLOAT_UNSIGNED_INT_24_8_REV)
    470 	{
    471 		DE_ASSERT(order == DS);
    472 		return 8;
    473 	}
    474 	else
    475 	{
    476 		int numChannels	= 0;
    477 		int channelSize	= 0;
    478 
    479 		switch (order)
    480 		{
    481 			case R:			numChannels = 1;	break;
    482 			case A:			numChannels = 1;	break;
    483 			case I:			numChannels = 1;	break;
    484 			case L:			numChannels = 1;	break;
    485 			case LA:		numChannels = 2;	break;
    486 			case RG:		numChannels = 2;	break;
    487 			case RA:		numChannels = 2;	break;
    488 			case RGB:		numChannels = 3;	break;
    489 			case RGBA:		numChannels = 4;	break;
    490 			case ARGB:		numChannels = 4;	break;
    491 			case BGRA:		numChannels = 4;	break;
    492 			case sRGB:		numChannels = 3;	break;
    493 			case sRGBA:		numChannels = 4;	break;
    494 			case D:			numChannels = 1;	break;
    495 			case S:			numChannels = 1;	break;
    496 			case DS:		numChannels = 2;	break;
    497 			default:		DE_ASSERT(DE_FALSE);
    498 		}
    499 
    500 		switch (type)
    501 		{
    502 			case SNORM_INT8:		channelSize = 1;	break;
    503 			case SNORM_INT16:		channelSize = 2;	break;
    504 			case SNORM_INT32:		channelSize = 4;	break;
    505 			case UNORM_INT8:		channelSize = 1;	break;
    506 			case UNORM_INT16:		channelSize = 2;	break;
    507 			case UNORM_INT32:		channelSize = 4;	break;
    508 			case SIGNED_INT8:		channelSize = 1;	break;
    509 			case SIGNED_INT16:		channelSize = 2;	break;
    510 			case SIGNED_INT32:		channelSize = 4;	break;
    511 			case UNSIGNED_INT8:		channelSize = 1;	break;
    512 			case UNSIGNED_INT16:	channelSize = 2;	break;
    513 			case UNSIGNED_INT32:	channelSize = 4;	break;
    514 			case HALF_FLOAT:		channelSize = 2;	break;
    515 			case FLOAT:				channelSize = 4;	break;
    516 			default:				DE_ASSERT(DE_FALSE);
    517 		}
    518 
    519 		return numChannels*channelSize;
    520 	}
    521 }
    522 
    523 ConstPixelBufferAccess::ConstPixelBufferAccess (void)
    524 	: m_width		(0)
    525 	, m_height		(0)
    526 	, m_depth		(0)
    527 	, m_rowPitch	(0)
    528 	, m_slicePitch	(0)
    529 	, m_data		(DE_NULL)
    530 {
    531 }
    532 
    533 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, const void* data)
    534 	: m_format		(format)
    535 	, m_width		(width)
    536 	, m_height		(height)
    537 	, m_depth		(depth)
    538 	, m_rowPitch	(width*format.getPixelSize())
    539 	, m_slicePitch	(m_rowPitch*height)
    540 	, m_data		((void*)data)
    541 {
    542 }
    543 
    544 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, const void* data)
    545 	: m_format		(format)
    546 	, m_width		(width)
    547 	, m_height		(height)
    548 	, m_depth		(depth)
    549 	, m_rowPitch	(rowPitch)
    550 	, m_slicePitch	(slicePitch)
    551 	, m_data		((void*)data)
    552 {
    553 }
    554 
    555 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureLevel& level)
    556 	: m_format		(level.getFormat())
    557 	, m_width		(level.getWidth())
    558 	, m_height		(level.getHeight())
    559 	, m_depth		(level.getDepth())
    560 	, m_rowPitch	(m_width*m_format.getPixelSize())
    561 	, m_slicePitch	(m_rowPitch*m_height)
    562 	, m_data		((void*)level.getPtr())
    563 {
    564 }
    565 
    566 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data)
    567 	: ConstPixelBufferAccess(format, width, height, depth, data)
    568 {
    569 }
    570 
    571 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, void* data)
    572 	: ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, data)
    573 {
    574 }
    575 
    576 PixelBufferAccess::PixelBufferAccess (TextureLevel& level)
    577 	: ConstPixelBufferAccess(level)
    578 {
    579 }
    580 
    581 void PixelBufferAccess::setPixels (const void* buf, int bufSize) const
    582 {
    583 	DE_ASSERT(bufSize == getDataSize());
    584 	deMemcpy(getDataPtr(), buf, bufSize);
    585 }
    586 
    587 Vec4 ConstPixelBufferAccess::getPixel (int x, int y, int z) const
    588 {
    589 	DE_ASSERT(de::inBounds(x, 0, m_width));
    590 	DE_ASSERT(de::inBounds(y, 0, m_height));
    591 	DE_ASSERT(de::inBounds(z, 0, m_depth));
    592 
    593 	// Optimized fomats.
    594 	if (m_format.type == TextureFormat::UNORM_INT8)
    595 	{
    596 		if (m_format.order == TextureFormat::RGBA)
    597 			return readRGBA8888Float((const deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*4);
    598 		else if (m_format.order == TextureFormat::RGB)
    599 			return readRGB888Float((const deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*3);
    600 	}
    601 
    602 	int				pixelSize		= m_format.getPixelSize();
    603 	const deUint8*	pixelPtr		= (const deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
    604 
    605 #define UB16(OFFS, COUNT)		((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
    606 #define UB32(OFFS, COUNT)		((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
    607 #define NB16(OFFS, COUNT)		channelToNormFloat(UB16(OFFS, COUNT), (COUNT))
    608 #define NB32(OFFS, COUNT)		channelToNormFloat(UB32(OFFS, COUNT), (COUNT))
    609 
    610 	// Packed formats.
    611 	switch (m_format.type)
    612 	{
    613 		case TextureFormat::UNORM_SHORT_565:			return Vec4(NB16(11,  5), NB16( 5,  6), NB16( 0,  5), 1.0f);
    614 		case TextureFormat::UNORM_SHORT_555:			return Vec4(NB16(10,  5), NB16( 5,  5), NB16( 0,  5), 1.0f);
    615 		case TextureFormat::UNORM_SHORT_4444:			return Vec4(NB16(12,  4), NB16( 8,  4), NB16( 4,  4), NB16( 0, 4));
    616 		case TextureFormat::UNORM_SHORT_5551:			return Vec4(NB16(11,  5), NB16( 6,  5), NB16( 1,  5), NB16( 0, 1));
    617 		case TextureFormat::UNORM_INT_101010:			return Vec4(NB32(22, 10), NB32(12, 10), NB32( 2, 10), 1.0f);
    618 		case TextureFormat::UNORM_INT_1010102_REV:		return Vec4(NB32( 0, 10), NB32(10, 10), NB32(20, 10), NB32(30, 2));
    619 		case TextureFormat::UNSIGNED_INT_1010102_REV:	return UVec4(UB32(0, 10), UB32(10, 10), UB32(20, 10), UB32(30, 2)).cast<float>();
    620 		case TextureFormat::UNSIGNED_INT_999_E5_REV:	return unpackRGB999E5(*((const deUint32*)pixelPtr));
    621 
    622 		case TextureFormat::UNSIGNED_INT_24_8:
    623 			switch (m_format.order)
    624 			{
    625 				// \note Stencil is always ignored.
    626 				case TextureFormat::D:	return Vec4(NB32(8, 24), 0.0f, 0.0f, 1.0f);
    627 				case TextureFormat::DS:	return Vec4(NB32(8, 24), 0.0f, 0.0f, 1.0f /* (float)UB32(0, 8) */);
    628 				default:
    629 					DE_ASSERT(false);
    630 			}
    631 
    632 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
    633 		{
    634 			DE_ASSERT(m_format.order == TextureFormat::DS);
    635 			float	d	= *((const float*)pixelPtr);
    636 			// \note Stencil is ignored.
    637 //			deUint8	s	= *((const deUint32*)(pixelPtr+4)) & 0xff;
    638 			return Vec4(d, 0.0f, 0.0f, 1.0f);
    639 		}
    640 
    641 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
    642 			return Vec4(Float11(UB32(0, 11)).asFloat(), Float11(UB32(11, 11)).asFloat(), Float10(UB32(22, 10)).asFloat(), 1.0f);
    643 
    644 		default:
    645 			break;
    646 	}
    647 
    648 #undef NB16
    649 #undef NB32
    650 #undef UB16
    651 #undef UB32
    652 
    653 	// Generic path.
    654 	Vec4			result;
    655 	const Channel*	channelMap	= getChannelReadMap(m_format.order);
    656 	int				channelSize	= getChannelSize(m_format.type);
    657 
    658 	for (int c = 0; c < 4; c++)
    659 	{
    660 		Channel map = channelMap[c];
    661 		if (map == CHANNEL_ZERO)
    662 			result[c] = 0.0f;
    663 		else if (map == CHANNEL_ONE)
    664 			result[c] = 1.0f;
    665 		else
    666 			result[c] = channelToFloat(pixelPtr + channelSize*((int)map), m_format.type);
    667 	}
    668 
    669 	return result;
    670 }
    671 
    672 IVec4 ConstPixelBufferAccess::getPixelInt (int x, int y, int z) const
    673 {
    674 	DE_ASSERT(de::inBounds(x, 0, m_width));
    675 	DE_ASSERT(de::inBounds(y, 0, m_height));
    676 	DE_ASSERT(de::inBounds(z, 0, m_depth));
    677 
    678 	int				pixelSize		= m_format.getPixelSize();
    679 	const deUint8*	pixelPtr		= (const deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
    680 	IVec4			result;
    681 
    682 	// Optimized fomats.
    683 	if (m_format.type == TextureFormat::UNORM_INT8)
    684 	{
    685 		if (m_format.order == TextureFormat::RGBA)		return readRGBA8888Int(pixelPtr);
    686 		else if (m_format.order == TextureFormat::RGB)	return readRGB888Int(pixelPtr);
    687 	}
    688 
    689 #define U16(OFFS, COUNT)		((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
    690 #define U32(OFFS, COUNT)		((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
    691 
    692 	switch (m_format.type)
    693 	{
    694 		case TextureFormat::UNORM_SHORT_565:			return UVec4(U16(11,  5), U16( 5,  6), U16( 0,  5), 1).cast<int>();
    695 		case TextureFormat::UNORM_SHORT_555:			return UVec4(U16(10,  5), U16( 5,  5), U16( 0,  5), 1).cast<int>();
    696 		case TextureFormat::UNORM_SHORT_4444:			return UVec4(U16(12,  4), U16( 8,  4), U16( 4,  4), U16( 0, 4)).cast<int>();
    697 		case TextureFormat::UNORM_SHORT_5551:			return UVec4(U16(11,  5), U16( 6,  5), U16( 1,  5), U16( 0, 1)).cast<int>();
    698 		case TextureFormat::UNORM_INT_101010:			return UVec4(U32(22, 10), U32(12, 10), U32( 2, 10), 1).cast<int>();
    699 		case TextureFormat::UNORM_INT_1010102_REV:		return UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)).cast<int>();
    700 		case TextureFormat::UNSIGNED_INT_1010102_REV:	return UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)).cast<int>();
    701 
    702 		case TextureFormat::UNSIGNED_INT_24_8:
    703 			switch (m_format.order)
    704 			{
    705 				case TextureFormat::D:	return UVec4(U32(8, 24), 0, 0, 1).cast<int>();
    706 				case TextureFormat::S:	return UVec4(0, 0, 0, U32(8, 24)).cast<int>();
    707 				case TextureFormat::DS:	return UVec4(U32(8, 24), 0, 0, U32(0, 8)).cast<int>();
    708 				default:
    709 					DE_ASSERT(false);
    710 			}
    711 
    712 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
    713 		{
    714 			DE_ASSERT(m_format.order == TextureFormat::DS);
    715 			float	d	= *((const float*)pixelPtr);
    716 			deUint8	s	= *((const deUint32*)(pixelPtr+4)) & 0xffu;
    717 			// \note Returns bit-representation of depth floating-point value.
    718 			return UVec4(tcu::Float32(d).bits(), 0, 0, s).cast<int>();
    719 		}
    720 
    721 		default:
    722 			break; // To generic path.
    723 	}
    724 
    725 #undef U16
    726 #undef U32
    727 
    728 	// Generic path.
    729 	const Channel*	channelMap	= getChannelReadMap(m_format.order);
    730 	int				channelSize	= getChannelSize(m_format.type);
    731 
    732 	for (int c = 0; c < 4; c++)
    733 	{
    734 		Channel map = channelMap[c];
    735 		if (map == CHANNEL_ZERO)
    736 			result[c] = 0;
    737 		else if (map == CHANNEL_ONE)
    738 			result[c] = 1;
    739 		else
    740 			result[c] = channelToInt(pixelPtr + channelSize*((int)map), m_format.type);
    741 	}
    742 
    743 	return result;
    744 }
    745 
    746 template<>
    747 Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
    748 {
    749 	return getPixel(x, y, z);
    750 }
    751 
    752 template<>
    753 IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
    754 {
    755 	return getPixelInt(x, y, z);
    756 }
    757 
    758 template<>
    759 UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
    760 {
    761 	return getPixelUint(x, y, z);
    762 }
    763 
    764 float ConstPixelBufferAccess::getPixDepth (int x, int y, int z) const
    765 {
    766 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
    767 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
    768 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
    769 
    770 	int			pixelSize	= m_format.getPixelSize();
    771 	deUint8*	pixelPtr	= (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
    772 
    773 #define UB32(OFFS, COUNT) ((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
    774 #define NB32(OFFS, COUNT) channelToNormFloat(UB32(OFFS, COUNT), (COUNT))
    775 
    776 	DE_ASSERT(m_format.order == TextureFormat::DS || m_format.order == TextureFormat::D);
    777 
    778 	switch (m_format.type)
    779 	{
    780 		case TextureFormat::UNSIGNED_INT_24_8:
    781 			switch (m_format.order)
    782 			{
    783 				case TextureFormat::D:
    784 				case TextureFormat::DS: // \note Fall-through.
    785 					return NB32(8, 24);
    786 				default:
    787 					DE_ASSERT(false);
    788 					return 0.0f;
    789 			}
    790 
    791 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
    792 			DE_ASSERT(m_format.order == TextureFormat::DS);
    793 			return *((const float*)pixelPtr);
    794 
    795 		default:
    796 			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
    797 			return channelToFloat(pixelPtr, m_format.type);
    798 	}
    799 
    800 #undef UB32
    801 #undef NB32
    802 }
    803 
    804 int ConstPixelBufferAccess::getPixStencil (int x, int y, int z) const
    805 {
    806 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
    807 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
    808 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
    809 
    810 	int			pixelSize	= m_format.getPixelSize();
    811 	deUint8*	pixelPtr	= (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
    812 
    813 	switch (m_format.type)
    814 	{
    815 		case TextureFormat::UNSIGNED_INT_24_8:
    816 			switch (m_format.order)
    817 			{
    818 				case TextureFormat::S:		return (int)(*((const deUint32*)pixelPtr) >> 8);
    819 				case TextureFormat::DS:		return (int)(*((const deUint32*)pixelPtr) & 0xff);
    820 
    821 				default:
    822 					DE_ASSERT(false);
    823 					return 0;
    824 			}
    825 
    826 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
    827 			DE_ASSERT(m_format.order == TextureFormat::DS);
    828 			return *((const deUint32*)(pixelPtr+4)) & 0xff;
    829 
    830 		default:
    831 		{
    832 			if (m_format.order == TextureFormat::S)
    833 				return channelToInt(pixelPtr, m_format.type);
    834 			else
    835 			{
    836 				DE_ASSERT(m_format.order == TextureFormat::DS);
    837 				const int stencilChannelIndex = 3;
    838 				return channelToInt(pixelPtr + getChannelSize(m_format.type)*stencilChannelIndex, m_format.type);
    839 			}
    840 		}
    841 	}
    842 }
    843 
    844 void PixelBufferAccess::setPixel (const Vec4& color, int x, int y, int z) const
    845 {
    846 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
    847 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
    848 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
    849 
    850 	// Optimized fomats.
    851 	if (m_format.type == TextureFormat::UNORM_INT8)
    852 	{
    853 		if (m_format.order == TextureFormat::RGBA)
    854 		{
    855 			deUint8* const ptr = (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*4;
    856 			writeRGBA8888Float(ptr, color);
    857 			return;
    858 		}
    859 		else if (m_format.order == TextureFormat::RGB)
    860 		{
    861 			deUint8* const ptr = (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*3;
    862 			writeRGB888Float(ptr, color);
    863 			return;
    864 		}
    865 	}
    866 
    867 	const int		pixelSize	= m_format.getPixelSize();
    868 	deUint8* const	pixelPtr	= (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
    869 
    870 #define PN(VAL, OFFS, BITS)		(normFloatToChannel((VAL), (BITS)) << (OFFS))
    871 #define PU(VAL, OFFS, BITS)		(uintToChannel((VAL), (BITS)) << (OFFS))
    872 
    873 	switch (m_format.type)
    874 	{
    875 		case TextureFormat::UNORM_SHORT_565:		*((deUint16*)pixelPtr) = (deUint16)(PN(color[0], 11, 5) | PN(color[1], 5, 6) | PN(color[2], 0, 5));							break;
    876 		case TextureFormat::UNORM_SHORT_555:		*((deUint16*)pixelPtr) = (deUint16)(PN(color[0], 10, 5) | PN(color[1], 5, 5) | PN(color[2], 0, 5));							break;
    877 		case TextureFormat::UNORM_SHORT_4444:		*((deUint16*)pixelPtr) = (deUint16)(PN(color[0], 12, 4) | PN(color[1], 8, 4) | PN(color[2], 4, 4) | PN(color[3], 0, 4));	break;
    878 		case TextureFormat::UNORM_SHORT_5551:		*((deUint16*)pixelPtr) = (deUint16)(PN(color[0], 11, 5) | PN(color[1], 6, 5) | PN(color[2], 1, 5) | PN(color[3], 0, 1));	break;
    879 		case TextureFormat::UNORM_INT_101010:		*((deUint32*)pixelPtr) = PN(color[0], 22, 10) | PN(color[1], 12, 10) | PN(color[2], 2, 10);									break;
    880 		case TextureFormat::UNORM_INT_1010102_REV:	*((deUint32*)pixelPtr) = PN(color[0],  0, 10) | PN(color[1], 10, 10) | PN(color[2], 20, 10) | PN(color[3], 30, 2);			break;
    881 
    882 		case TextureFormat::UNSIGNED_INT_1010102_REV:
    883 		{
    884 			UVec4 u = color.cast<deUint32>();
    885 			*((deUint32*)pixelPtr) = PU(u[0], 0, 10) | PU(u[1], 10, 10) |PU(u[2], 20, 10) | PU(u[3], 30, 2);
    886 			break;
    887 		}
    888 
    889 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
    890 			*((deUint32*)pixelPtr) = Float11(color[0]).bits() | (Float11(color[1]).bits() << 11) | (Float10(color[2]).bits() << 22);
    891 			break;
    892 
    893 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
    894 			*((deUint32*)pixelPtr) = packRGB999E5(color);
    895 			break;
    896 
    897 		case TextureFormat::UNSIGNED_INT_24_8:
    898 			switch (m_format.order)
    899 			{
    900 				case TextureFormat::D:		*((deUint32*)pixelPtr) = PN(color[0], 8, 24);									break;
    901 				case TextureFormat::S:		*((deUint32*)pixelPtr) = PN(color[3], 8, 24);									break;
    902 				case TextureFormat::DS:		*((deUint32*)pixelPtr) = PN(color[0], 8, 24) | PU((deUint32)color[3], 0, 8);	break;
    903 				default:
    904 					DE_ASSERT(false);
    905 			}
    906 			break;
    907 
    908 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
    909 			DE_ASSERT(m_format.order == TextureFormat::DS);
    910 			*((float*)pixelPtr)			= color[0];
    911 			*((deUint32*)(pixelPtr+4))	= PU((deUint32)color[3], 0, 8);
    912 			break;
    913 
    914 		case TextureFormat::FLOAT:
    915 			if (m_format.order == TextureFormat::D)
    916 			{
    917 				*((float*)pixelPtr) = color[0];
    918 				break;
    919 			}
    920 			// else fall-through to default case!
    921 
    922 		default:
    923 		{
    924 			// Generic path.
    925 			int			numChannels	= getNumUsedChannels(m_format.order);
    926 			const int*	map			= getChannelWriteMap(m_format.order);
    927 			int			channelSize	= getChannelSize(m_format.type);
    928 
    929 			for (int c = 0; c < numChannels; c++)
    930 				floatToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
    931 
    932 			break;
    933 		}
    934 	}
    935 
    936 #undef PN
    937 #undef PU
    938 }
    939 
    940 void PixelBufferAccess::setPixel (const IVec4& color, int x, int y, int z) const
    941 {
    942 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
    943 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
    944 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
    945 
    946 	int			pixelSize	= m_format.getPixelSize();
    947 	deUint8*	pixelPtr	= (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
    948 
    949 	// Optimized fomats.
    950 	if (m_format.type == TextureFormat::UNORM_INT8)
    951 	{
    952 		if (m_format.order == TextureFormat::RGBA)		{ writeRGBA8888Int(pixelPtr, color);	return; }
    953 		else if (m_format.order == TextureFormat::RGB)	{ writeRGB888Int(pixelPtr, color);		return; }
    954 	}
    955 
    956 #define PU(VAL, OFFS, BITS)		(uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
    957 
    958 	switch (m_format.type)
    959 	{
    960 		case TextureFormat::UNORM_SHORT_565:			*((deUint16*)pixelPtr) = (deUint16)(PU(color[0], 11, 5) | PU(color[1], 5, 6) | PU(color[2], 0, 5));							break;
    961 		case TextureFormat::UNORM_SHORT_555:			*((deUint16*)pixelPtr) = (deUint16)(PU(color[0], 10, 5) | PU(color[1], 5, 5) | PU(color[2], 0, 5));							break;
    962 		case TextureFormat::UNORM_SHORT_4444:			*((deUint16*)pixelPtr) = (deUint16)(PU(color[0], 12, 4) | PU(color[1], 8, 4) | PU(color[2], 4, 4) | PU(color[3], 0, 4));	break;
    963 		case TextureFormat::UNORM_SHORT_5551:			*((deUint16*)pixelPtr) = (deUint16)(PU(color[0], 11, 5) | PU(color[1], 6, 5) | PU(color[2], 1, 5) | PU(color[3], 0, 1));	break;
    964 		case TextureFormat::UNORM_INT_101010:			*((deUint32*)pixelPtr) = PU(color[0], 22, 10) | PU(color[1], 12, 10) | PU(color[2], 2, 10);									break;
    965 		case TextureFormat::UNORM_INT_1010102_REV:		*((deUint32*)pixelPtr) = PU(color[0],  0, 10) | PU(color[1], 10, 10) | PU(color[2], 20, 10) | PU(color[3], 30, 2);			break;
    966 		case TextureFormat::UNSIGNED_INT_1010102_REV:	*((deUint32*)pixelPtr) = PU(color[0],  0, 10) | PU(color[1], 10, 10) | PU(color[2], 20, 10) | PU(color[3], 30, 2);			break;
    967 
    968 		case TextureFormat::UNSIGNED_INT_24_8:
    969 			switch (m_format.order)
    970 			{
    971 				case TextureFormat::D:		*((deUint32*)pixelPtr) = PU(color[0], 8, 24);										break;
    972 				case TextureFormat::S:		*((deUint32*)pixelPtr) = PU(color[3], 8, 24);										break;
    973 				case TextureFormat::DS:		*((deUint32*)pixelPtr) = PU(color[0], 8, 24) | PU((deUint32)color[3], 0, 8);		break;
    974 				default:
    975 					DE_ASSERT(false);
    976 			}
    977 			break;
    978 
    979 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
    980 			DE_ASSERT(m_format.order == TextureFormat::DS);
    981 			*((deUint32*)pixelPtr)		= color[0];
    982 			*((deUint32*)(pixelPtr+4))	= PU((deUint32)color[3], 0, 8);
    983 			break;
    984 
    985 		default:
    986 		{
    987 			// Generic path.
    988 			int			numChannels	= getNumUsedChannels(m_format.order);
    989 			const int*	map			= getChannelWriteMap(m_format.order);
    990 			int			channelSize	= getChannelSize(m_format.type);
    991 
    992 			for (int c = 0; c < numChannels; c++)
    993 				intToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
    994 
    995 			break;
    996 		}
    997 	}
    998 
    999 #undef PU
   1000 }
   1001 
   1002 void PixelBufferAccess::setPixDepth (float depth, int x, int y, int z) const
   1003 {
   1004 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
   1005 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
   1006 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
   1007 
   1008 	int			pixelSize	= m_format.getPixelSize();
   1009 	deUint8*	pixelPtr	= (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
   1010 
   1011 #define PN(VAL, OFFS, BITS) (normFloatToChannel((VAL), (BITS)) << (OFFS))
   1012 
   1013 	switch (m_format.type)
   1014 	{
   1015 		case TextureFormat::UNSIGNED_INT_24_8:
   1016 			switch (m_format.order)
   1017 			{
   1018 				case TextureFormat::D:		*((deUint32*)pixelPtr) = PN(depth, 8, 24);											break;
   1019 				case TextureFormat::DS:		*((deUint32*)pixelPtr) = (*((deUint32*)pixelPtr) & 0x000000ff) | PN(depth, 8, 24);	break;
   1020 				default:
   1021 					DE_ASSERT(false);
   1022 			}
   1023 			break;
   1024 
   1025 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
   1026 			DE_ASSERT(m_format.order == TextureFormat::DS);
   1027 			*((float*)pixelPtr) = depth;
   1028 			break;
   1029 
   1030 		default:
   1031 			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
   1032 			floatToChannel(pixelPtr, depth, m_format.type);
   1033 			break;
   1034 	}
   1035 
   1036 #undef PN
   1037 }
   1038 
   1039 void PixelBufferAccess::setPixStencil (int stencil, int x, int y, int z) const
   1040 {
   1041 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
   1042 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
   1043 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
   1044 
   1045 	int			pixelSize	= m_format.getPixelSize();
   1046 	deUint8*	pixelPtr	= (deUint8*)getDataPtr() + z*m_slicePitch + y*m_rowPitch + x*pixelSize;
   1047 
   1048 #define PU(VAL, OFFS, BITS) (uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
   1049 
   1050 	switch (m_format.type)
   1051 	{
   1052 		case TextureFormat::UNSIGNED_INT_24_8:
   1053 			switch (m_format.order)
   1054 			{
   1055 				case TextureFormat::S:		*((deUint32*)pixelPtr) = PU(stencil, 8, 24);										break;
   1056 				case TextureFormat::DS:		*((deUint32*)pixelPtr) = (*((deUint32*)pixelPtr) & 0xffffff00) | PU(stencil, 0, 8);	break;
   1057 				default:
   1058 					DE_ASSERT(false);
   1059 			}
   1060 			break;
   1061 
   1062 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
   1063 			DE_ASSERT(m_format.order == TextureFormat::DS);
   1064 			*((deUint32*)(pixelPtr+4))	= PU((deUint32)stencil, 0, 8);
   1065 			break;
   1066 
   1067 		default:
   1068 			if (m_format.order == TextureFormat::S)
   1069 				intToChannel(pixelPtr, stencil, m_format.type);
   1070 			else
   1071 			{
   1072 				DE_ASSERT(m_format.order == TextureFormat::DS);
   1073 				const int stencilChannelIndex = 3;
   1074 				intToChannel(pixelPtr + getChannelSize(m_format.type)*stencilChannelIndex, stencil, m_format.type);
   1075 			}
   1076 
   1077 			break;
   1078 	}
   1079 
   1080 #undef PU
   1081 }
   1082 
   1083 static inline int imod (int a, int b)
   1084 {
   1085 	int m = a % b;
   1086 	return m < 0 ? m + b : m;
   1087 }
   1088 
   1089 static inline int mirror (int a)
   1090 {
   1091 	return a >= 0.0f ? a : -(1 + a);
   1092 }
   1093 
   1094 // Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
   1095 static inline float rint (float a)
   1096 {
   1097 	DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
   1098 
   1099 	float		fracVal		= deFloatFrac(a);
   1100 
   1101 	if (fracVal != 0.5f)
   1102 		return deFloatRound(a); // Ordinary case.
   1103 
   1104 	float	floorVal	= a - fracVal;
   1105 	bool	roundUp		= (deInt64)floorVal % 2 != 0;
   1106 
   1107 	return floorVal + (roundUp ? 1.0f : 0.0f);
   1108 }
   1109 
   1110 static inline int wrap (Sampler::WrapMode mode, int c, int size)
   1111 {
   1112 	switch (mode)
   1113 	{
   1114 		case tcu::Sampler::CLAMP_TO_BORDER:
   1115 			return deClamp32(c, -1, size);
   1116 
   1117 		case tcu::Sampler::CLAMP_TO_EDGE:
   1118 			return deClamp32(c, 0, size-1);
   1119 
   1120 		case tcu::Sampler::REPEAT_GL:
   1121 			return imod(c, size);
   1122 
   1123 		case tcu::Sampler::REPEAT_CL:
   1124 			return imod(c, size);
   1125 
   1126 		case tcu::Sampler::MIRRORED_REPEAT_GL:
   1127 			return (size - 1) - mirror(imod(c, 2*size) - size);
   1128 
   1129 		case tcu::Sampler::MIRRORED_REPEAT_CL:
   1130 			return deClamp32(c, 0, size-1); // \note Actual mirroring done already in unnormalization function.
   1131 
   1132 		default:
   1133 			DE_ASSERT(DE_FALSE);
   1134 			return 0;
   1135 	}
   1136 }
   1137 
   1138 // Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL wrap modes; otherwise ordinary unnormalization.
   1139 static inline float unnormalize (Sampler::WrapMode mode, float c, int size)
   1140 {
   1141 	switch (mode)
   1142 	{
   1143 		case tcu::Sampler::CLAMP_TO_EDGE:
   1144 		case tcu::Sampler::CLAMP_TO_BORDER:
   1145 		case tcu::Sampler::REPEAT_GL:
   1146 		case tcu::Sampler::MIRRORED_REPEAT_GL: // Fall-through (ordinary case).
   1147 			return (float)size*c;
   1148 
   1149 		case tcu::Sampler::REPEAT_CL:
   1150 			return (float)size * (c - deFloatFloor(c));
   1151 
   1152 		case tcu::Sampler::MIRRORED_REPEAT_CL:
   1153 			return (float)size * deFloatAbs(c - 2.0f * rint(0.5f * c));
   1154 
   1155 		default:
   1156 			DE_ASSERT(DE_FALSE);
   1157 			return 0.0f;
   1158 	}
   1159 }
   1160 
   1161 static inline bool isSRGB (TextureFormat format)
   1162 {
   1163 	return format.order == TextureFormat::sRGB || format.order == TextureFormat::sRGBA;
   1164 }
   1165 
   1166 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
   1167 {
   1168 	const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
   1169 
   1170 	if (format.order == TextureFormat::D)
   1171 	{
   1172 		// depth internal formats cannot be non-normalized integers
   1173 		return channelClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
   1174 	}
   1175 	else if (format.order == TextureFormat::DS)
   1176 	{
   1177 		// combined formats have no single channel class, detect format manually
   1178 		switch (format.type)
   1179 		{
   1180 			case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return false;
   1181 			case tcu::TextureFormat::UNSIGNED_INT_24_8:				return true;
   1182 
   1183 			default:
   1184 			{
   1185 				// unknown format
   1186 				DE_ASSERT(false);
   1187 				return true;
   1188 			}
   1189 		}
   1190 	}
   1191 
   1192 	return false;
   1193 }
   1194 
   1195 // Texel lookup with color conversion.
   1196 static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, int k)
   1197 {
   1198 	Vec4 p = access.getPixel(i, j, k);
   1199 	return isSRGB(access.getFormat()) ? sRGBToLinear(p) : p;
   1200 }
   1201 
   1202 static inline float execCompare (const tcu::Vec4& color, Sampler::CompareMode compare, int chanNdx, float ref_, bool isFixedPoint)
   1203 {
   1204 	const bool	clampValues	= isFixedPoint;	// if comparing against a floating point texture, ref (and value) is not clamped
   1205 	const float	cmp			= (clampValues) ? (de::clamp(color[chanNdx], 0.0f, 1.0f)) : (color[chanNdx]);
   1206 	const float	ref			= (clampValues) ? (de::clamp(ref_, 0.0f, 1.0f)) : (ref_);
   1207 	bool		res			= false;
   1208 
   1209 	switch (compare)
   1210 	{
   1211 		case Sampler::COMPAREMODE_LESS:				res = ref < cmp;	break;
   1212 		case Sampler::COMPAREMODE_LESS_OR_EQUAL:	res = ref <= cmp;	break;
   1213 		case Sampler::COMPAREMODE_GREATER:			res = ref > cmp;	break;
   1214 		case Sampler::COMPAREMODE_GREATER_OR_EQUAL:	res = ref >= cmp;	break;
   1215 		case Sampler::COMPAREMODE_EQUAL:			res = ref == cmp;	break;
   1216 		case Sampler::COMPAREMODE_NOT_EQUAL:		res = ref != cmp;	break;
   1217 		case Sampler::COMPAREMODE_ALWAYS:			res = true;			break;
   1218 		case Sampler::COMPAREMODE_NEVER:			res = false;		break;
   1219 		default:
   1220 			DE_ASSERT(false);
   1221 	}
   1222 
   1223 	return res ? 1.0f : 0.0f;
   1224 }
   1225 
   1226 static Vec4 sampleNearest1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, int level)
   1227 {
   1228 	int width	= access.getWidth();
   1229 	int x		= deFloorFloatToInt32(u);
   1230 
   1231 	// Check for CLAMP_TO_BORDER.
   1232 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)))
   1233 		return sampler.borderColor;
   1234 
   1235 	int i = wrap(sampler.wrapS, x, width);
   1236 
   1237 	return lookup(access, i, level, 0);
   1238 }
   1239 
   1240 static Vec4 sampleNearest1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
   1241 {
   1242 	int width	= access.getWidth();
   1243 
   1244 	int x = deFloorFloatToInt32(u)+offset.x();
   1245 
   1246 	// Check for CLAMP_TO_BORDER.
   1247 	if (sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))
   1248 		return sampler.borderColor;
   1249 
   1250 	int i = wrap(sampler.wrapS, x, width);
   1251 
   1252 	return lookup(access, i, offset.y(), 0);
   1253 }
   1254 
   1255 static Vec4 sampleNearest2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, int depth)
   1256 {
   1257 	int width	= access.getWidth();
   1258 	int height	= access.getHeight();
   1259 
   1260 	int x = deFloorFloatToInt32(u);
   1261 	int y = deFloorFloatToInt32(v);
   1262 
   1263 	// Check for CLAMP_TO_BORDER.
   1264 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
   1265 		(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)))
   1266 		return sampler.borderColor;
   1267 
   1268 	int i = wrap(sampler.wrapS, x, width);
   1269 	int j = wrap(sampler.wrapT, y, height);
   1270 
   1271 	return lookup(access, i, j, depth);
   1272 }
   1273 
   1274 static Vec4 sampleNearest2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
   1275 {
   1276 	int width	= access.getWidth();
   1277 	int height	= access.getHeight();
   1278 
   1279 	int x = deFloorFloatToInt32(u)+offset.x();
   1280 	int y = deFloorFloatToInt32(v)+offset.y();
   1281 
   1282 	// Check for CLAMP_TO_BORDER.
   1283 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
   1284 		(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)))
   1285 		return sampler.borderColor;
   1286 
   1287 	int i = wrap(sampler.wrapS, x, width);
   1288 	int j = wrap(sampler.wrapT, y, height);
   1289 
   1290 	return lookup(access, i, j, offset.z());
   1291 }
   1292 
   1293 static Vec4 sampleNearest3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w)
   1294 {
   1295 	int width	= access.getWidth();
   1296 	int height	= access.getHeight();
   1297 	int depth	= access.getDepth();
   1298 
   1299 	int x = deFloorFloatToInt32(u);
   1300 	int y = deFloorFloatToInt32(v);
   1301 	int z = deFloorFloatToInt32(w);
   1302 
   1303 	// Check for CLAMP_TO_BORDER.
   1304 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))	||
   1305 		(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height))	||
   1306 		(sampler.wrapR == Sampler::CLAMP_TO_BORDER && !deInBounds32(z, 0, depth)))
   1307 		return sampler.borderColor;
   1308 
   1309 	int i = wrap(sampler.wrapS, x, width);
   1310 	int j = wrap(sampler.wrapT, y, height);
   1311 	int k = wrap(sampler.wrapR, z, depth);
   1312 
   1313 	return lookup(access, i, j, k);
   1314 }
   1315 
   1316 static Vec4 sampleNearest3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
   1317 {
   1318 	int width	= access.getWidth();
   1319 	int height	= access.getHeight();
   1320 	int depth	= access.getDepth();
   1321 
   1322 	int x = deFloorFloatToInt32(u)+offset.x();
   1323 	int y = deFloorFloatToInt32(v)+offset.y();
   1324 	int z = deFloorFloatToInt32(w)+offset.z();
   1325 
   1326 	// Check for CLAMP_TO_BORDER.
   1327 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))	||
   1328 		(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height))	||
   1329 		(sampler.wrapR == Sampler::CLAMP_TO_BORDER && !deInBounds32(z, 0, depth)))
   1330 		return sampler.borderColor;
   1331 
   1332 	int i = wrap(sampler.wrapS, x, width);
   1333 	int j = wrap(sampler.wrapT, y, height);
   1334 	int k = wrap(sampler.wrapR, z, depth);
   1335 
   1336 	return lookup(access, i, j, k);
   1337 }
   1338 
   1339 static Vec4 sampleLinear1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, int level)
   1340 {
   1341 	int w = access.getWidth();
   1342 
   1343 	int x0 = deFloorFloatToInt32(u-0.5f);
   1344 	int x1 = x0+1;
   1345 
   1346 	int i0 = wrap(sampler.wrapS, x0, w);
   1347 	int i1 = wrap(sampler.wrapS, x1, w);
   1348 
   1349 	float a = deFloatFrac(u-0.5f);
   1350 
   1351 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
   1352 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
   1353 
   1354 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1355 	Vec4 p0 = i0UseBorder ? sampler.borderColor : lookup(access, i0, level, 0);
   1356 	Vec4 p1 = i1UseBorder ? sampler.borderColor : lookup(access, i1, level, 0);
   1357 
   1358 	// Interpolate.
   1359 	return p0 * (1.0f-a) + a * p1;
   1360 }
   1361 
   1362 static Vec4 sampleLinear1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
   1363 {
   1364 	int w = access.getWidth();
   1365 
   1366 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
   1367 	int x1 = x0+1;
   1368 
   1369 	int i0 = wrap(sampler.wrapS, x0, w);
   1370 	int i1 = wrap(sampler.wrapS, x1, w);
   1371 
   1372 	float a = deFloatFrac(u-0.5f);
   1373 
   1374 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
   1375 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
   1376 
   1377 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1378 	Vec4 p0 = i0UseBorder ? sampler.borderColor : lookup(access, i0, offset.y(), 0);
   1379 	Vec4 p1 = i1UseBorder ? sampler.borderColor : lookup(access, i1, offset.y(), 0);
   1380 
   1381 	// Interpolate.
   1382 	return p0 * (1.0f - a) + p1 * a;
   1383 }
   1384 
   1385 static Vec4 sampleLinear2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, int depth)
   1386 {
   1387 	int w = access.getWidth();
   1388 	int h = access.getHeight();
   1389 
   1390 	int x0 = deFloorFloatToInt32(u-0.5f);
   1391 	int x1 = x0+1;
   1392 	int y0 = deFloorFloatToInt32(v-0.5f);
   1393 	int y1 = y0+1;
   1394 
   1395 	int i0 = wrap(sampler.wrapS, x0, w);
   1396 	int i1 = wrap(sampler.wrapS, x1, w);
   1397 	int j0 = wrap(sampler.wrapT, y0, h);
   1398 	int j1 = wrap(sampler.wrapT, y1, h);
   1399 
   1400 	float a = deFloatFrac(u-0.5f);
   1401 	float b = deFloatFrac(v-0.5f);
   1402 
   1403 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
   1404 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
   1405 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
   1406 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
   1407 
   1408 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1409 	Vec4 p00 = (i0UseBorder || j0UseBorder) ? sampler.borderColor : lookup(access, i0, j0, depth);
   1410 	Vec4 p10 = (i1UseBorder || j0UseBorder) ? sampler.borderColor : lookup(access, i1, j0, depth);
   1411 	Vec4 p01 = (i0UseBorder || j1UseBorder) ? sampler.borderColor : lookup(access, i0, j1, depth);
   1412 	Vec4 p11 = (i1UseBorder || j1UseBorder) ? sampler.borderColor : lookup(access, i1, j1, depth);
   1413 
   1414 	// Interpolate.
   1415 	return (p00*(1.0f-a)*(1.0f-b)) +
   1416 		   (p10*(     a)*(1.0f-b)) +
   1417 		   (p01*(1.0f-a)*(     b)) +
   1418 		   (p11*(     a)*(     b));
   1419 }
   1420 
   1421 static Vec4 sampleLinear2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
   1422 {
   1423 	int w = access.getWidth();
   1424 	int h = access.getHeight();
   1425 
   1426 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
   1427 	int x1 = x0+1;
   1428 	int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
   1429 	int y1 = y0+1;
   1430 
   1431 	int i0 = wrap(sampler.wrapS, x0, w);
   1432 	int i1 = wrap(sampler.wrapS, x1, w);
   1433 	int j0 = wrap(sampler.wrapT, y0, h);
   1434 	int j1 = wrap(sampler.wrapT, y1, h);
   1435 
   1436 	float a = deFloatFrac(u-0.5f);
   1437 	float b = deFloatFrac(v-0.5f);
   1438 
   1439 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
   1440 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
   1441 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
   1442 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
   1443 
   1444 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1445 	Vec4 p00 = (i0UseBorder || j0UseBorder) ? sampler.borderColor : lookup(access, i0, j0, offset.z());
   1446 	Vec4 p10 = (i1UseBorder || j0UseBorder) ? sampler.borderColor : lookup(access, i1, j0, offset.z());
   1447 	Vec4 p01 = (i0UseBorder || j1UseBorder) ? sampler.borderColor : lookup(access, i0, j1, offset.z());
   1448 	Vec4 p11 = (i1UseBorder || j1UseBorder) ? sampler.borderColor : lookup(access, i1, j1, offset.z());
   1449 
   1450 	// Interpolate.
   1451 	return (p00*(1.0f-a)*(1.0f-b)) +
   1452 		   (p10*(     a)*(1.0f-b)) +
   1453 		   (p01*(1.0f-a)*(     b)) +
   1454 		   (p11*(     a)*(     b));
   1455 }
   1456 
   1457 static float sampleLinear1DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, const IVec2& offset, bool isFixedPointDepthFormat)
   1458 {
   1459 	int w = access.getWidth();
   1460 
   1461 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
   1462 	int x1 = x0+1;
   1463 
   1464 	int i0 = wrap(sampler.wrapS, x0, w);
   1465 	int i1 = wrap(sampler.wrapS, x1, w);
   1466 
   1467 	float a = deFloatFrac(u-0.5f);
   1468 
   1469 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
   1470 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
   1471 
   1472 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1473 	Vec4 p0Clr = i0UseBorder  ? sampler.borderColor : lookup(access, i0, offset.y(), 0);
   1474 	Vec4 p1Clr = i1UseBorder  ? sampler.borderColor : lookup(access, i1, offset.y(), 0);
   1475 
   1476 	// Execute comparisons.
   1477 	float p0 = execCompare(p0Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
   1478 	float p1 = execCompare(p1Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
   1479 
   1480 	// Interpolate.
   1481 	return (p0 * (1.0f - a)) + (p1 * a);
   1482 }
   1483 
   1484 static float sampleLinear2DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, float v, const IVec3& offset, bool isFixedPointDepthFormat)
   1485 {
   1486 	int w = access.getWidth();
   1487 	int h = access.getHeight();
   1488 
   1489 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
   1490 	int x1 = x0+1;
   1491 	int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
   1492 	int y1 = y0+1;
   1493 
   1494 	int i0 = wrap(sampler.wrapS, x0, w);
   1495 	int i1 = wrap(sampler.wrapS, x1, w);
   1496 	int j0 = wrap(sampler.wrapT, y0, h);
   1497 	int j1 = wrap(sampler.wrapT, y1, h);
   1498 
   1499 	float a = deFloatFrac(u-0.5f);
   1500 	float b = deFloatFrac(v-0.5f);
   1501 
   1502 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
   1503 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
   1504 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
   1505 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
   1506 
   1507 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1508 	Vec4 p00Clr = (i0UseBorder || j0UseBorder) ? sampler.borderColor : lookup(access, i0, j0, offset.z());
   1509 	Vec4 p10Clr = (i1UseBorder || j0UseBorder) ? sampler.borderColor : lookup(access, i1, j0, offset.z());
   1510 	Vec4 p01Clr = (i0UseBorder || j1UseBorder) ? sampler.borderColor : lookup(access, i0, j1, offset.z());
   1511 	Vec4 p11Clr = (i1UseBorder || j1UseBorder) ? sampler.borderColor : lookup(access, i1, j1, offset.z());
   1512 
   1513 	// Execute comparisons.
   1514 	float p00 = execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
   1515 	float p10 = execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
   1516 	float p01 = execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
   1517 	float p11 = execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
   1518 
   1519 	// Interpolate.
   1520 	return (p00*(1.0f-a)*(1.0f-b)) +
   1521 		   (p10*(     a)*(1.0f-b)) +
   1522 		   (p01*(1.0f-a)*(     b)) +
   1523 		   (p11*(     a)*(     b));
   1524 }
   1525 
   1526 static Vec4 sampleLinear3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w)
   1527 {
   1528 	int width	= access.getWidth();
   1529 	int height	= access.getHeight();
   1530 	int depth	= access.getDepth();
   1531 
   1532 	int x0 = deFloorFloatToInt32(u-0.5f);
   1533 	int x1 = x0+1;
   1534 	int y0 = deFloorFloatToInt32(v-0.5f);
   1535 	int y1 = y0+1;
   1536 	int z0 = deFloorFloatToInt32(w-0.5f);
   1537 	int z1 = z0+1;
   1538 
   1539 	int i0 = wrap(sampler.wrapS, x0, width);
   1540 	int i1 = wrap(sampler.wrapS, x1, width);
   1541 	int j0 = wrap(sampler.wrapT, y0, height);
   1542 	int j1 = wrap(sampler.wrapT, y1, height);
   1543 	int k0 = wrap(sampler.wrapR, z0, depth);
   1544 	int k1 = wrap(sampler.wrapR, z1, depth);
   1545 
   1546 	float a = deFloatFrac(u-0.5f);
   1547 	float b = deFloatFrac(v-0.5f);
   1548 	float c = deFloatFrac(w-0.5f);
   1549 
   1550 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, width);
   1551 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, width);
   1552 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, height);
   1553 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, height);
   1554 	bool k0UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k0, 0, depth);
   1555 	bool k1UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k1, 0, depth);
   1556 
   1557 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1558 	Vec4 p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i0, j0, k0);
   1559 	Vec4 p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i1, j0, k0);
   1560 	Vec4 p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i0, j1, k0);
   1561 	Vec4 p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i1, j1, k0);
   1562 	Vec4 p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i0, j0, k1);
   1563 	Vec4 p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i1, j0, k1);
   1564 	Vec4 p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i0, j1, k1);
   1565 	Vec4 p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i1, j1, k1);
   1566 
   1567 	// Interpolate.
   1568 	return (p000*(1.0f-a)*(1.0f-b)*(1.0f-c)) +
   1569 		   (p100*(     a)*(1.0f-b)*(1.0f-c)) +
   1570 		   (p010*(1.0f-a)*(     b)*(1.0f-c)) +
   1571 		   (p110*(     a)*(     b)*(1.0f-c)) +
   1572 		   (p001*(1.0f-a)*(1.0f-b)*(     c)) +
   1573 		   (p101*(     a)*(1.0f-b)*(     c)) +
   1574 		   (p011*(1.0f-a)*(     b)*(     c)) +
   1575 		   (p111*(     a)*(     b)*(     c));
   1576 }
   1577 
   1578 static Vec4 sampleLinear3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
   1579 {
   1580 	int width	= access.getWidth();
   1581 	int height	= access.getHeight();
   1582 	int depth	= access.getDepth();
   1583 
   1584 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
   1585 	int x1 = x0+1;
   1586 	int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
   1587 	int y1 = y0+1;
   1588 	int z0 = deFloorFloatToInt32(w-0.5f)+offset.z();
   1589 	int z1 = z0+1;
   1590 
   1591 	int i0 = wrap(sampler.wrapS, x0, width);
   1592 	int i1 = wrap(sampler.wrapS, x1, width);
   1593 	int j0 = wrap(sampler.wrapT, y0, height);
   1594 	int j1 = wrap(sampler.wrapT, y1, height);
   1595 	int k0 = wrap(sampler.wrapR, z0, depth);
   1596 	int k1 = wrap(sampler.wrapR, z1, depth);
   1597 
   1598 	float a = deFloatFrac(u-0.5f);
   1599 	float b = deFloatFrac(v-0.5f);
   1600 	float c = deFloatFrac(w-0.5f);
   1601 
   1602 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, width);
   1603 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, width);
   1604 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, height);
   1605 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, height);
   1606 	bool k0UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k0, 0, depth);
   1607 	bool k1UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k1, 0, depth);
   1608 
   1609 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
   1610 	Vec4 p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i0, j0, k0);
   1611 	Vec4 p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i1, j0, k0);
   1612 	Vec4 p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i0, j1, k0);
   1613 	Vec4 p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : lookup(access, i1, j1, k0);
   1614 	Vec4 p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i0, j0, k1);
   1615 	Vec4 p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i1, j0, k1);
   1616 	Vec4 p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i0, j1, k1);
   1617 	Vec4 p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : lookup(access, i1, j1, k1);
   1618 
   1619 	// Interpolate.
   1620 	return (p000*(1.0f-a)*(1.0f-b)*(1.0f-c)) +
   1621 		   (p100*(     a)*(1.0f-b)*(1.0f-c)) +
   1622 		   (p010*(1.0f-a)*(     b)*(1.0f-c)) +
   1623 		   (p110*(     a)*(     b)*(1.0f-c)) +
   1624 		   (p001*(1.0f-a)*(1.0f-b)*(     c)) +
   1625 		   (p101*(     a)*(1.0f-b)*(     c)) +
   1626 		   (p011*(1.0f-a)*(     b)*(     c)) +
   1627 		   (p111*(     a)*(     b)*(     c));
   1628 }
   1629 
   1630 Vec4 ConstPixelBufferAccess::sample1D (const Sampler& sampler, Sampler::FilterMode filter, float s, int level) const
   1631 {
   1632 	DE_ASSERT(de::inBounds(level, 0, m_height));
   1633 
   1634 	// Non-normalized coordinates.
   1635 	float u = s;
   1636 
   1637 	if (sampler.normalizedCoords)
   1638 		u = unnormalize(sampler.wrapS, s, m_width);
   1639 
   1640 	switch (filter)
   1641 	{
   1642 		case Sampler::NEAREST:	return sampleNearest1D	(*this, sampler, u, level);
   1643 		case Sampler::LINEAR:	return sampleLinear1D	(*this, sampler, u, level);
   1644 		default:
   1645 			DE_ASSERT(DE_FALSE);
   1646 			return Vec4(0.0f);
   1647 	}
   1648 }
   1649 
   1650 Vec4 ConstPixelBufferAccess::sample2D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, int depth) const
   1651 {
   1652 	DE_ASSERT(de::inBounds(depth, 0, m_depth));
   1653 
   1654 	// Non-normalized coordinates.
   1655 	float u = s;
   1656 	float v = t;
   1657 
   1658 	if (sampler.normalizedCoords)
   1659 	{
   1660 		u = unnormalize(sampler.wrapS, s, m_width);
   1661 		v = unnormalize(sampler.wrapT, t, m_height);
   1662 	}
   1663 
   1664 	switch (filter)
   1665 	{
   1666 		case Sampler::NEAREST:	return sampleNearest2D	(*this, sampler, u, v, depth);
   1667 		case Sampler::LINEAR:	return sampleLinear2D	(*this, sampler, u, v, depth);
   1668 		default:
   1669 			DE_ASSERT(DE_FALSE);
   1670 			return Vec4(0.0f);
   1671 	}
   1672 }
   1673 
   1674 Vec4 ConstPixelBufferAccess::sample1DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, const IVec2& offset) const
   1675 {
   1676 	DE_ASSERT(de::inBounds(offset.y(), 0, m_width));
   1677 
   1678 	// Non-normalized coordinates.
   1679 	float u = s;
   1680 
   1681 	if (sampler.normalizedCoords)
   1682 		u = unnormalize(sampler.wrapS, s, m_width);
   1683 
   1684 	switch (filter)
   1685 	{
   1686 		case Sampler::NEAREST:	return sampleNearest1D	(*this, sampler, u, offset);
   1687 		case Sampler::LINEAR:	return sampleLinear1D	(*this, sampler, u, offset);
   1688 		default:
   1689 			DE_ASSERT(DE_FALSE);
   1690 			return Vec4(0.0f);
   1691 	}
   1692 }
   1693 
   1694 Vec4 ConstPixelBufferAccess::sample2DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, const IVec3& offset) const
   1695 {
   1696 	DE_ASSERT(de::inBounds(offset.z(), 0, m_depth));
   1697 
   1698 	// Non-normalized coordinates.
   1699 	float u = s;
   1700 	float v = t;
   1701 
   1702 	if (sampler.normalizedCoords)
   1703 	{
   1704 		u = unnormalize(sampler.wrapS, s, m_width);
   1705 		v = unnormalize(sampler.wrapT, t, m_height);
   1706 	}
   1707 
   1708 	switch (filter)
   1709 	{
   1710 		case Sampler::NEAREST:	return sampleNearest2D	(*this, sampler, u, v, offset);
   1711 		case Sampler::LINEAR:	return sampleLinear2D	(*this, sampler, u, v, offset);
   1712 		default:
   1713 			DE_ASSERT(DE_FALSE);
   1714 			return Vec4(0.0f);
   1715 	}
   1716 }
   1717 
   1718 float ConstPixelBufferAccess::sample1DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, const IVec2& offset) const
   1719 {
   1720 	DE_ASSERT(de::inBounds(offset.y(), 0, m_height));
   1721 
   1722 	// Format information for comparison function
   1723 	const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
   1724 
   1725 	// Non-normalized coordinates.
   1726 	float u = s;
   1727 
   1728 	if (sampler.normalizedCoords)
   1729 		u = unnormalize(sampler.wrapS, s, m_width);
   1730 
   1731 	switch (filter)
   1732 	{
   1733 		case Sampler::NEAREST:	return execCompare(sampleNearest1D(*this, sampler, u, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
   1734 		case Sampler::LINEAR:	return sampleLinear1DCompare(*this, sampler, ref, u, offset, isFixedPointDepth);
   1735 		default:
   1736 			DE_ASSERT(DE_FALSE);
   1737 			return 0.0f;
   1738 	}
   1739 }
   1740 
   1741 float ConstPixelBufferAccess::sample2DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, float t, const IVec3& offset) const
   1742 {
   1743 	DE_ASSERT(de::inBounds(offset.z(), 0, m_depth));
   1744 
   1745 	// Format information for comparison function
   1746 	const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
   1747 
   1748 	// Non-normalized coordinates.
   1749 	float u = s;
   1750 	float v = t;
   1751 
   1752 	if (sampler.normalizedCoords)
   1753 	{
   1754 		u = unnormalize(sampler.wrapS, s, m_width);
   1755 		v = unnormalize(sampler.wrapT, t, m_height);
   1756 	}
   1757 
   1758 	switch (filter)
   1759 	{
   1760 		case Sampler::NEAREST:	return execCompare(sampleNearest2D(*this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
   1761 		case Sampler::LINEAR:	return sampleLinear2DCompare(*this, sampler, ref, u, v, offset, isFixedPointDepth);
   1762 		default:
   1763 			DE_ASSERT(DE_FALSE);
   1764 			return 0.0f;
   1765 	}
   1766 }
   1767 
   1768 Vec4 ConstPixelBufferAccess::sample3D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r) const
   1769 {
   1770 	// Non-normalized coordinates.
   1771 	float u = s;
   1772 	float v = t;
   1773 	float w = r;
   1774 
   1775 	if (sampler.normalizedCoords)
   1776 	{
   1777 		u = unnormalize(sampler.wrapS, s, m_width);
   1778 		v = unnormalize(sampler.wrapT, t, m_height);
   1779 		w = unnormalize(sampler.wrapR, r, m_depth);
   1780 	}
   1781 
   1782 	switch (filter)
   1783 	{
   1784 		case Sampler::NEAREST:	return sampleNearest3D	(*this, sampler, u, v, w);
   1785 		case Sampler::LINEAR:	return sampleLinear3D	(*this, sampler, u, v, w);
   1786 		default:
   1787 			DE_ASSERT(DE_FALSE);
   1788 			return Vec4(0.0f);
   1789 	}
   1790 }
   1791 
   1792 Vec4 ConstPixelBufferAccess::sample3DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r, const IVec3& offset) const
   1793 {
   1794 	// Non-normalized coordinates.
   1795 	float u = s;
   1796 	float v = t;
   1797 	float w = r;
   1798 
   1799 	if (sampler.normalizedCoords)
   1800 	{
   1801 		u = unnormalize(sampler.wrapS, s, m_width);
   1802 		v = unnormalize(sampler.wrapT, t, m_height);
   1803 		w = unnormalize(sampler.wrapR, r, m_depth);
   1804 	}
   1805 
   1806 	switch (filter)
   1807 	{
   1808 		case Sampler::NEAREST:	return sampleNearest3D	(*this, sampler, u, v, w, offset);
   1809 		case Sampler::LINEAR:	return sampleLinear3D	(*this, sampler, u, v, w, offset);
   1810 		default:
   1811 			DE_ASSERT(DE_FALSE);
   1812 			return Vec4(0.0f);
   1813 	}
   1814 }
   1815 
   1816 TextureLevel::TextureLevel (void)
   1817 	: m_format	()
   1818 	, m_width	(0)
   1819 	, m_height	(0)
   1820 	, m_depth	(0)
   1821 {
   1822 }
   1823 
   1824 TextureLevel::TextureLevel (const TextureFormat& format)
   1825 	: m_format	(format)
   1826 	, m_width	(0)
   1827 	, m_height	(0)
   1828 	, m_depth	(0)
   1829 {
   1830 }
   1831 
   1832 TextureLevel::TextureLevel (const TextureFormat& format, int width, int height, int depth)
   1833 	: m_format	(format)
   1834 	, m_width	(0)
   1835 	, m_height	(0)
   1836 	, m_depth	(0)
   1837 {
   1838 	setSize(width, height, depth);
   1839 }
   1840 
   1841 TextureLevel::~TextureLevel (void)
   1842 {
   1843 }
   1844 
   1845 void TextureLevel::setStorage (const TextureFormat& format, int width, int height, int depth)
   1846 {
   1847 	m_format = format;
   1848 	setSize(width, height, depth);
   1849 }
   1850 
   1851 void TextureLevel::setSize (int width, int height, int depth)
   1852 {
   1853 	int pixelSize = m_format.getPixelSize();
   1854 
   1855 	m_width		= width;
   1856 	m_height	= height;
   1857 	m_depth		= depth;
   1858 
   1859 	m_data.setStorage(m_width*m_height*m_depth*pixelSize);
   1860 }
   1861 
   1862 Vec4 sampleLevelArray1D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, int depth, float lod)
   1863 {
   1864 	bool					magnified	= lod <= sampler.lodThreshold;
   1865 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   1866 
   1867 	switch (filterMode)
   1868 	{
   1869 		case Sampler::NEAREST:	return levels[0].sample1D(sampler, filterMode, s, depth);
   1870 		case Sampler::LINEAR:	return levels[0].sample1D(sampler, filterMode, s, depth);
   1871 
   1872 		case Sampler::NEAREST_MIPMAP_NEAREST:
   1873 		case Sampler::LINEAR_MIPMAP_NEAREST:
   1874 		{
   1875 			int					maxLevel	= (int)numLevels-1;
   1876 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   1877 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   1878 
   1879 			return levels[level].sample1D(sampler, levelFilter, s, depth);
   1880 		}
   1881 
   1882 		case Sampler::NEAREST_MIPMAP_LINEAR:
   1883 		case Sampler::LINEAR_MIPMAP_LINEAR:
   1884 		{
   1885 			int					maxLevel	= (int)numLevels-1;
   1886 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   1887 			int					level1		= de::min(maxLevel, level0 + 1);
   1888 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   1889 			float				f			= deFloatFrac(lod);
   1890 			tcu::Vec4			t0			= levels[level0].sample1D(sampler, levelFilter, s, depth);
   1891 			tcu::Vec4			t1			= levels[level1].sample1D(sampler, levelFilter, s, depth);
   1892 
   1893 			return t0*(1.0f - f) + t1*f;
   1894 		}
   1895 
   1896 		default:
   1897 			DE_ASSERT(DE_FALSE);
   1898 			return Vec4(0.0f);
   1899 	}
   1900 }
   1901 
   1902 Vec4 sampleLevelArray1DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float lod, const IVec2& offset)
   1903 {
   1904 	bool					magnified	= lod <= sampler.lodThreshold;
   1905 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   1906 
   1907 	switch (filterMode)
   1908 	{
   1909 		case Sampler::NEAREST:	return levels[0].sample1DOffset(sampler, filterMode, s, offset);
   1910 		case Sampler::LINEAR:	return levels[0].sample1DOffset(sampler, filterMode, s, offset);
   1911 
   1912 		case Sampler::NEAREST_MIPMAP_NEAREST:
   1913 		case Sampler::LINEAR_MIPMAP_NEAREST:
   1914 		{
   1915 			int					maxLevel	= (int)numLevels-1;
   1916 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   1917 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   1918 
   1919 			return levels[level].sample1DOffset(sampler, levelFilter, s, offset);
   1920 		}
   1921 
   1922 		case Sampler::NEAREST_MIPMAP_LINEAR:
   1923 		case Sampler::LINEAR_MIPMAP_LINEAR:
   1924 		{
   1925 			int					maxLevel	= (int)numLevels-1;
   1926 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   1927 			int					level1		= de::min(maxLevel, level0 + 1);
   1928 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   1929 			float				f			= deFloatFrac(lod);
   1930 			tcu::Vec4			t0			= levels[level0].sample1DOffset(sampler, levelFilter, s, offset);
   1931 			tcu::Vec4			t1			= levels[level1].sample1DOffset(sampler, levelFilter, s, offset);
   1932 
   1933 			return t0*(1.0f - f) + t1*f;
   1934 		}
   1935 
   1936 		default:
   1937 			DE_ASSERT(DE_FALSE);
   1938 			return Vec4(0.0f);
   1939 	}
   1940 }
   1941 
   1942 Vec4 sampleLevelArray2D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, int depth, float lod)
   1943 {
   1944 	bool					magnified	= lod <= sampler.lodThreshold;
   1945 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   1946 
   1947 	switch (filterMode)
   1948 	{
   1949 		case Sampler::NEAREST:	return levels[0].sample2D(sampler, filterMode, s, t, depth);
   1950 		case Sampler::LINEAR:	return levels[0].sample2D(sampler, filterMode, s, t, depth);
   1951 
   1952 		case Sampler::NEAREST_MIPMAP_NEAREST:
   1953 		case Sampler::LINEAR_MIPMAP_NEAREST:
   1954 		{
   1955 			int					maxLevel	= (int)numLevels-1;
   1956 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   1957 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   1958 
   1959 			return levels[level].sample2D(sampler, levelFilter, s, t, depth);
   1960 		}
   1961 
   1962 		case Sampler::NEAREST_MIPMAP_LINEAR:
   1963 		case Sampler::LINEAR_MIPMAP_LINEAR:
   1964 		{
   1965 			int					maxLevel	= (int)numLevels-1;
   1966 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   1967 			int					level1		= de::min(maxLevel, level0 + 1);
   1968 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   1969 			float				f			= deFloatFrac(lod);
   1970 			tcu::Vec4			t0			= levels[level0].sample2D(sampler, levelFilter, s, t, depth);
   1971 			tcu::Vec4			t1			= levels[level1].sample2D(sampler, levelFilter, s, t, depth);
   1972 
   1973 			return t0*(1.0f - f) + t1*f;
   1974 		}
   1975 
   1976 		default:
   1977 			DE_ASSERT(DE_FALSE);
   1978 			return Vec4(0.0f);
   1979 	}
   1980 }
   1981 
   1982 Vec4 sampleLevelArray2DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float lod, const IVec3& offset)
   1983 {
   1984 	bool					magnified	= lod <= sampler.lodThreshold;
   1985 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   1986 
   1987 	switch (filterMode)
   1988 	{
   1989 		case Sampler::NEAREST:	return levels[0].sample2DOffset(sampler, filterMode, s, t, offset);
   1990 		case Sampler::LINEAR:	return levels[0].sample2DOffset(sampler, filterMode, s, t, offset);
   1991 
   1992 		case Sampler::NEAREST_MIPMAP_NEAREST:
   1993 		case Sampler::LINEAR_MIPMAP_NEAREST:
   1994 		{
   1995 			int					maxLevel	= (int)numLevels-1;
   1996 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   1997 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   1998 
   1999 			return levels[level].sample2DOffset(sampler, levelFilter, s, t, offset);
   2000 		}
   2001 
   2002 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2003 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2004 		{
   2005 			int					maxLevel	= (int)numLevels-1;
   2006 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2007 			int					level1		= de::min(maxLevel, level0 + 1);
   2008 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2009 			float				f			= deFloatFrac(lod);
   2010 			tcu::Vec4			t0			= levels[level0].sample2DOffset(sampler, levelFilter, s, t, offset);
   2011 			tcu::Vec4			t1			= levels[level1].sample2DOffset(sampler, levelFilter, s, t, offset);
   2012 
   2013 			return t0*(1.0f - f) + t1*f;
   2014 		}
   2015 
   2016 		default:
   2017 			DE_ASSERT(DE_FALSE);
   2018 			return Vec4(0.0f);
   2019 	}
   2020 }
   2021 
   2022 Vec4 sampleLevelArray3D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod)
   2023 {
   2024 	bool					magnified	= lod <= sampler.lodThreshold;
   2025 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2026 
   2027 	switch (filterMode)
   2028 	{
   2029 		case Sampler::NEAREST:	return levels[0].sample3D(sampler, filterMode, s, t, r);
   2030 		case Sampler::LINEAR:	return levels[0].sample3D(sampler, filterMode, s, t, r);
   2031 
   2032 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2033 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2034 		{
   2035 			int					maxLevel	= (int)numLevels-1;
   2036 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2037 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2038 
   2039 			return levels[level].sample3D(sampler, levelFilter, s, t, r);
   2040 		}
   2041 
   2042 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2043 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2044 		{
   2045 			int					maxLevel	= (int)numLevels-1;
   2046 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2047 			int					level1		= de::min(maxLevel, level0 + 1);
   2048 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2049 			float				f			= deFloatFrac(lod);
   2050 			tcu::Vec4			t0			= levels[level0].sample3D(sampler, levelFilter, s, t, r);
   2051 			tcu::Vec4			t1			= levels[level1].sample3D(sampler, levelFilter, s, t, r);
   2052 
   2053 			return t0*(1.0f - f) + t1*f;
   2054 		}
   2055 
   2056 		default:
   2057 			DE_ASSERT(DE_FALSE);
   2058 			return Vec4(0.0f);
   2059 	}
   2060 }
   2061 
   2062 Vec4 sampleLevelArray3DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod, const IVec3& offset)
   2063 {
   2064 	bool					magnified	= lod <= sampler.lodThreshold;
   2065 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2066 
   2067 	switch (filterMode)
   2068 	{
   2069 		case Sampler::NEAREST:	return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
   2070 		case Sampler::LINEAR:	return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
   2071 
   2072 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2073 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2074 		{
   2075 			int					maxLevel	= (int)numLevels-1;
   2076 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2077 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2078 
   2079 			return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
   2080 		}
   2081 
   2082 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2083 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2084 		{
   2085 			int					maxLevel	= (int)numLevels-1;
   2086 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2087 			int					level1		= de::min(maxLevel, level0 + 1);
   2088 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2089 			float				f			= deFloatFrac(lod);
   2090 			tcu::Vec4			t0			= levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset);
   2091 			tcu::Vec4			t1			= levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset);
   2092 
   2093 			return t0*(1.0f - f) + t1*f;
   2094 		}
   2095 
   2096 		default:
   2097 			DE_ASSERT(DE_FALSE);
   2098 			return Vec4(0.0f);
   2099 	}
   2100 }
   2101 
   2102 float sampleLevelArray1DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float lod, const IVec2& offset)
   2103 {
   2104 	bool					magnified	= lod <= sampler.lodThreshold;
   2105 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2106 
   2107 	switch (filterMode)
   2108 	{
   2109 		case Sampler::NEAREST:	return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
   2110 		case Sampler::LINEAR:	return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
   2111 
   2112 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2113 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2114 		{
   2115 			int					maxLevel	= (int)numLevels-1;
   2116 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2117 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2118 
   2119 			return levels[level].sample1DCompare(sampler, levelFilter, ref, s, offset);
   2120 		}
   2121 
   2122 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2123 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2124 		{
   2125 			int					maxLevel	= (int)numLevels-1;
   2126 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2127 			int					level1		= de::min(maxLevel, level0 + 1);
   2128 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2129 			float				f			= deFloatFrac(lod);
   2130 			float				t0			= levels[level0].sample1DCompare(sampler, levelFilter, ref, s, offset);
   2131 			float				t1			= levels[level1].sample1DCompare(sampler, levelFilter, ref, s, offset);
   2132 
   2133 			return t0*(1.0f - f) + t1*f;
   2134 		}
   2135 
   2136 		default:
   2137 			DE_ASSERT(DE_FALSE);
   2138 			return 0.0f;
   2139 	}
   2140 }
   2141 
   2142 float sampleLevelArray2DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float t, float lod, const IVec3& offset)
   2143 {
   2144 	bool					magnified	= lod <= sampler.lodThreshold;
   2145 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2146 
   2147 	switch (filterMode)
   2148 	{
   2149 		case Sampler::NEAREST:	return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
   2150 		case Sampler::LINEAR:	return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
   2151 
   2152 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2153 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2154 		{
   2155 			int					maxLevel	= (int)numLevels-1;
   2156 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2157 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2158 
   2159 			return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
   2160 		}
   2161 
   2162 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2163 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2164 		{
   2165 			int					maxLevel	= (int)numLevels-1;
   2166 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2167 			int					level1		= de::min(maxLevel, level0 + 1);
   2168 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2169 			float				f			= deFloatFrac(lod);
   2170 			float				t0			= levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
   2171 			float				t1			= levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
   2172 
   2173 			return t0*(1.0f - f) + t1*f;
   2174 		}
   2175 
   2176 		default:
   2177 			DE_ASSERT(DE_FALSE);
   2178 			return 0.0f;
   2179 	}
   2180 }
   2181 
   2182 Vec4 gatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
   2183 {
   2184 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
   2185 	DE_ASSERT(de::inBounds(componentNdx, 0, 4));
   2186 
   2187 	const int		w	= src.getWidth();
   2188 	const int		h	= src.getHeight();
   2189 	const float		u	= unnormalize(sampler.wrapS, s, w);
   2190 	const float		v	= unnormalize(sampler.wrapT, t, h);
   2191 	const int		x0	= deFloorFloatToInt32(u-0.5f);
   2192 	const int		y0	= deFloorFloatToInt32(v-0.5f);
   2193 
   2194 	IVec2 samplePositions[4];
   2195 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(samplePositions); i++)
   2196 		samplePositions[i] = IVec2(wrap(sampler.wrapS, x0 + offsets[i].x(), w),
   2197 								   wrap(sampler.wrapT, y0 + offsets[i].y(), h));
   2198 
   2199 	Vec4 result;
   2200 	for (int i = 0; i < 4; i++)
   2201 	{
   2202 		const Vec4 pixel = lookup(src, samplePositions[i].x(), samplePositions[i].y(), depth);
   2203 		result[i] = pixel[componentNdx];
   2204 	}
   2205 
   2206 	return result;
   2207 }
   2208 
   2209 Vec4 gatherArray2DOffsetsCompare (const ConstPixelBufferAccess& src, const Sampler& sampler, float ref, float s, float t, int depth, const IVec2 (&offsets)[4])
   2210 {
   2211 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
   2212 	DE_ASSERT(src.getFormat().order == TextureFormat::D || src.getFormat().order == TextureFormat::DS);
   2213 	DE_ASSERT(sampler.compareChannel == 0);
   2214 
   2215 	Sampler noCompareSampler = sampler;
   2216 	noCompareSampler.compare = Sampler::COMPAREMODE_NONE;
   2217 
   2218 	const Vec4	gathered			= gatherArray2DOffsets(src, noCompareSampler, s, t, depth, 0 /* component 0: depth */, offsets);
   2219 	const bool	isFixedPoint		= isFixedPointDepthTextureFormat(src.getFormat());
   2220 	Vec4 result;
   2221 	for (int i = 0; i < 4; i++)
   2222 		result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
   2223 
   2224 	return result;
   2225 }
   2226 
   2227 static Vec4 sampleCubeSeamlessNearest (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float s, float t, int depth)
   2228 {
   2229 	Sampler clampingSampler = sampler;
   2230 	clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
   2231 	clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
   2232 	return faceAccess.sample2D(clampingSampler, Sampler::NEAREST, s, t, depth);
   2233 }
   2234 
   2235 CubeFace selectCubeFace (const Vec3& coords)
   2236 {
   2237 	const float	x	= coords.x();
   2238 	const float	y	= coords.y();
   2239 	const float	z	= coords.z();
   2240 	const float	ax	= deFloatAbs(x);
   2241 	const float	ay	= deFloatAbs(y);
   2242 	const float	az	= deFloatAbs(z);
   2243 
   2244 	if (ay < ax && az < ax)
   2245 		return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
   2246 	else if (ax < ay && az < ay)
   2247 		return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
   2248 	else if (ax < az && ay < az)
   2249 		return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
   2250 	else
   2251 	{
   2252 		// Some of the components are equal. Use tie-breaking rule.
   2253 		if (ax == ay)
   2254 		{
   2255 			if (ax < az)
   2256 				return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
   2257 			else
   2258 				return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
   2259 		}
   2260 		else if (ax == az)
   2261 		{
   2262 			if (az < ay)
   2263 				return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
   2264 			else
   2265 				return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
   2266 		}
   2267 		else if (ay == az)
   2268 		{
   2269 			if (ay < ax)
   2270 				return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
   2271 			else
   2272 				return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
   2273 		}
   2274 		else
   2275 			return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
   2276 	}
   2277 }
   2278 
   2279 Vec2 projectToFace (CubeFace face, const Vec3& coord)
   2280 {
   2281 	const float	rx		= coord.x();
   2282 	const float	ry		= coord.y();
   2283 	const float	rz		= coord.z();
   2284 	float		sc		= 0.0f;
   2285 	float		tc		= 0.0f;
   2286 	float		ma		= 0.0f;
   2287 	float		s;
   2288 	float		t;
   2289 
   2290 	switch (face)
   2291 	{
   2292 		case CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break;
   2293 		case CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break;
   2294 		case CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break;
   2295 		case CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break;
   2296 		case CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break;
   2297 		case CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break;
   2298 		default:
   2299 			DE_ASSERT(DE_FALSE);
   2300 	}
   2301 
   2302 	// Compute s, t
   2303 	s = ((sc / ma) + 1.0f) / 2.0f;
   2304 	t = ((tc / ma) + 1.0f) / 2.0f;
   2305 
   2306 	return Vec2(s, t);
   2307 }
   2308 
   2309 CubeFaceFloatCoords getCubeFaceCoords (const Vec3& coords)
   2310 {
   2311 	const CubeFace face = selectCubeFace(coords);
   2312 	return CubeFaceFloatCoords(face, projectToFace(face, coords));
   2313 }
   2314 
   2315 // Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceIntCoords with face set to the appropriate neighboring face and coords transformed accordingly.
   2316 // \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face.
   2317 CubeFaceIntCoords remapCubeEdgeCoords (const CubeFaceIntCoords& origCoords, int size)
   2318 {
   2319 	bool uInBounds = de::inBounds(origCoords.s, 0, size);
   2320 	bool vInBounds = de::inBounds(origCoords.t, 0, size);
   2321 
   2322 	if (uInBounds && vInBounds)
   2323 		return origCoords;
   2324 
   2325 	if (!uInBounds && !vInBounds)
   2326 		return CubeFaceIntCoords(CUBEFACE_LAST, -1, -1);
   2327 
   2328 	IVec2 coords(wrap(Sampler::CLAMP_TO_BORDER, origCoords.s, size),
   2329 				 wrap(Sampler::CLAMP_TO_BORDER, origCoords.t, size));
   2330 	IVec3 canonizedCoords;
   2331 
   2332 	// Map the uv coordinates to canonized 3d coordinates.
   2333 
   2334 	switch (origCoords.face)
   2335 	{
   2336 		case CUBEFACE_NEGATIVE_X: canonizedCoords = IVec3(0,					size-1-coords.y(),	coords.x());			break;
   2337 		case CUBEFACE_POSITIVE_X: canonizedCoords = IVec3(size-1,				size-1-coords.y(),	size-1-coords.x());		break;
   2338 		case CUBEFACE_NEGATIVE_Y: canonizedCoords = IVec3(coords.x(),			0,					size-1-coords.y());		break;
   2339 		case CUBEFACE_POSITIVE_Y: canonizedCoords = IVec3(coords.x(),			size-1,				coords.y());			break;
   2340 		case CUBEFACE_NEGATIVE_Z: canonizedCoords = IVec3(size-1-coords.x(),	size-1-coords.y(),	0);						break;
   2341 		case CUBEFACE_POSITIVE_Z: canonizedCoords = IVec3(coords.x(),			size-1-coords.y(),	size-1);				break;
   2342 		default: DE_ASSERT(false);
   2343 	}
   2344 
   2345 	// Find an appropriate face to re-map the coordinates to.
   2346 
   2347 	if (canonizedCoords.x() == -1)
   2348 		return CubeFaceIntCoords(CUBEFACE_NEGATIVE_X, IVec2(canonizedCoords.z(), size-1-canonizedCoords.y()));
   2349 
   2350 	if (canonizedCoords.x() == size)
   2351 		return CubeFaceIntCoords(CUBEFACE_POSITIVE_X, IVec2(size-1-canonizedCoords.z(), size-1-canonizedCoords.y()));
   2352 
   2353 	if (canonizedCoords.y() == -1)
   2354 		return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Y, IVec2(canonizedCoords.x(), size-1-canonizedCoords.z()));
   2355 
   2356 	if (canonizedCoords.y() == size)
   2357 		return CubeFaceIntCoords(CUBEFACE_POSITIVE_Y, IVec2(canonizedCoords.x(), canonizedCoords.z()));
   2358 
   2359 	if (canonizedCoords.z() == -1)
   2360 		return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Z, IVec2(size-1-canonizedCoords.x(), size-1-canonizedCoords.y()));
   2361 
   2362 	if (canonizedCoords.z() == size)
   2363 		return CubeFaceIntCoords(CUBEFACE_POSITIVE_Z, IVec2(canonizedCoords.x(), size-1-canonizedCoords.y()));
   2364 
   2365 	DE_ASSERT(false);
   2366 	return CubeFaceIntCoords(CUBEFACE_LAST, IVec2(-1));
   2367 }
   2368 
   2369 static void getCubeLinearSamples (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, float u, float v, int depth, Vec4 (&dst)[4])
   2370 {
   2371 	DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
   2372 	int		size					= faceAccesses[0].getWidth();
   2373 	int		x0						= deFloorFloatToInt32(u-0.5f);
   2374 	int		x1						= x0+1;
   2375 	int		y0						= deFloorFloatToInt32(v-0.5f);
   2376 	int		y1						= y0+1;
   2377 	IVec2	baseSampleCoords[4]		=
   2378 	{
   2379 		IVec2(x0, y0),
   2380 		IVec2(x1, y0),
   2381 		IVec2(x0, y1),
   2382 		IVec2(x1, y1)
   2383 	};
   2384 	Vec4	sampleColors[4];
   2385 	bool	hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
   2386 
   2387 	// Find correct faces and coordinates for out-of-bounds sample coordinates.
   2388 
   2389 	for (int i = 0; i < 4; i++)
   2390 	{
   2391 		CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
   2392 		hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
   2393 		if (!hasBothCoordsOutOfBounds[i])
   2394 			sampleColors[i] = lookup(faceAccesses[coords.face], coords.s, coords.t, depth);
   2395 	}
   2396 
   2397 	// If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
   2398 	// \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
   2399 	//		 requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
   2400 	//		 must have this color as well.
   2401 
   2402 	{
   2403 		int bothOutOfBoundsNdx = -1;
   2404 		for (int i = 0; i < 4; i++)
   2405 		{
   2406 			if (hasBothCoordsOutOfBounds[i])
   2407 			{
   2408 				DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
   2409 				bothOutOfBoundsNdx = i;
   2410 			}
   2411 		}
   2412 		if (bothOutOfBoundsNdx != -1)
   2413 		{
   2414 			sampleColors[bothOutOfBoundsNdx] = Vec4(0.0f);
   2415 			for (int i = 0; i < 4; i++)
   2416 				if (i != bothOutOfBoundsNdx)
   2417 					sampleColors[bothOutOfBoundsNdx] += sampleColors[i];
   2418 
   2419 			sampleColors[bothOutOfBoundsNdx] = sampleColors[bothOutOfBoundsNdx] * (1.0f/3.0f);
   2420 		}
   2421 	}
   2422 
   2423 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(sampleColors); i++)
   2424 		dst[i] = sampleColors[i];
   2425 }
   2426 
   2427 // \todo [2014-02-19 pyry] Optimize faceAccesses
   2428 static Vec4 sampleCubeSeamlessLinear (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float s, float t, int depth)
   2429 {
   2430 	DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
   2431 
   2432 	int		size	= faceAccesses[0].getWidth();
   2433 	// Non-normalized coordinates.
   2434 	float	u		= s;
   2435 	float	v		= t;
   2436 
   2437 	if (sampler.normalizedCoords)
   2438 	{
   2439 		u = unnormalize(sampler.wrapS, s, size);
   2440 		v = unnormalize(sampler.wrapT, t, size);
   2441 	}
   2442 
   2443 	// Get sample colors.
   2444 
   2445 	Vec4 sampleColors[4];
   2446 	getCubeLinearSamples(faceAccesses, baseFace, u, v, depth, sampleColors);
   2447 
   2448 	// Interpolate.
   2449 
   2450 	float a = deFloatFrac(u-0.5f);
   2451 	float b = deFloatFrac(v-0.5f);
   2452 
   2453 	return (sampleColors[0]*(1.0f-a)*(1.0f-b)) +
   2454 		   (sampleColors[1]*(     a)*(1.0f-b)) +
   2455 		   (sampleColors[2]*(1.0f-a)*(     b)) +
   2456 		   (sampleColors[3]*(     a)*(     b));
   2457 }
   2458 
   2459 static Vec4 sampleLevelArrayCubeSeamless (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float s, float t, int depth, float lod)
   2460 {
   2461 	bool					magnified	= lod <= sampler.lodThreshold;
   2462 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2463 
   2464 	switch (filterMode)
   2465 	{
   2466 		case Sampler::NEAREST:
   2467 			return sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth);
   2468 
   2469 		case Sampler::LINEAR:
   2470 		{
   2471 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2472 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2473 				faceAccesses[i] = faces[i][0];
   2474 
   2475 			return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
   2476 		}
   2477 
   2478 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2479 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2480 		{
   2481 			int						maxLevel	= (int)numLevels-1;
   2482 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2483 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2484 
   2485 			if (levelFilter == Sampler::NEAREST)
   2486 				return sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
   2487 			else
   2488 			{
   2489 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2490 
   2491 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2492 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2493 					faceAccesses[i] = faces[i][level];
   2494 
   2495 				return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
   2496 			}
   2497 		}
   2498 
   2499 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2500 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2501 		{
   2502 			int						maxLevel	= (int)numLevels-1;
   2503 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2504 			int						level1		= de::min(maxLevel, level0 + 1);
   2505 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2506 			float					f			= deFloatFrac(lod);
   2507 			Vec4					t0;
   2508 			Vec4					t1;
   2509 
   2510 			if (levelFilter == Sampler::NEAREST)
   2511 			{
   2512 				t0 = sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
   2513 				t1 = sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
   2514 			}
   2515 			else
   2516 			{
   2517 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2518 
   2519 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
   2520 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
   2521 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2522 				{
   2523 					faceAccesses0[i] = faces[i][level0];
   2524 					faceAccesses1[i] = faces[i][level1];
   2525 				}
   2526 
   2527 				t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
   2528 				t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
   2529 			}
   2530 
   2531 			return t0*(1.0f - f) + t1*f;
   2532 		}
   2533 
   2534 		default:
   2535 			DE_ASSERT(DE_FALSE);
   2536 			return Vec4(0.0f);
   2537 	}
   2538 }
   2539 
   2540 static float sampleCubeSeamlessNearestCompare (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float ref, float s, float t, int depth = 0)
   2541 {
   2542 	Sampler clampingSampler = sampler;
   2543 	clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
   2544 	clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
   2545 	return faceAccess.sample2DCompare(clampingSampler, Sampler::NEAREST, ref, s, t, IVec3(0, 0, depth));
   2546 }
   2547 
   2548 static float sampleCubeSeamlessLinearCompare (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float ref, float s, float t)
   2549 {
   2550 	DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
   2551 
   2552 	int		size	= faceAccesses[0].getWidth();
   2553 	// Non-normalized coordinates.
   2554 	float	u		= s;
   2555 	float	v		= t;
   2556 
   2557 	if (sampler.normalizedCoords)
   2558 	{
   2559 		u = unnormalize(sampler.wrapS, s, size);
   2560 		v = unnormalize(sampler.wrapT, t, size);
   2561 	}
   2562 
   2563 	int			x0						= deFloorFloatToInt32(u-0.5f);
   2564 	int			x1						= x0+1;
   2565 	int			y0						= deFloorFloatToInt32(v-0.5f);
   2566 	int			y1						= y0+1;
   2567 	IVec2		baseSampleCoords[4]		=
   2568 	{
   2569 		IVec2(x0, y0),
   2570 		IVec2(x1, y0),
   2571 		IVec2(x0, y1),
   2572 		IVec2(x1, y1)
   2573 	};
   2574 	float		sampleRes[4];
   2575 	bool		hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
   2576 
   2577 	// Find correct faces and coordinates for out-of-bounds sample coordinates.
   2578 
   2579 	for (int i = 0; i < 4; i++)
   2580 	{
   2581 		CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
   2582 		hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
   2583 
   2584 		if (!hasBothCoordsOutOfBounds[i])
   2585 		{
   2586 			const bool isFixedPointDepth = isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
   2587 
   2588 			sampleRes[i] = execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
   2589 		}
   2590 	}
   2591 
   2592 	// If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
   2593 	// \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
   2594 	//		 requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
   2595 	//		 must have this color as well.
   2596 
   2597 	{
   2598 		int bothOutOfBoundsNdx = -1;
   2599 		for (int i = 0; i < 4; i++)
   2600 		{
   2601 			if (hasBothCoordsOutOfBounds[i])
   2602 			{
   2603 				DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
   2604 				bothOutOfBoundsNdx = i;
   2605 			}
   2606 		}
   2607 		if (bothOutOfBoundsNdx != -1)
   2608 		{
   2609 			sampleRes[bothOutOfBoundsNdx] = 0.0f;
   2610 			for (int i = 0; i < 4; i++)
   2611 				if (i != bothOutOfBoundsNdx)
   2612 					sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
   2613 
   2614 			sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0f/3.0f);
   2615 		}
   2616 	}
   2617 
   2618 	// Interpolate.
   2619 
   2620 	float a = deFloatFrac(u-0.5f);
   2621 	float b = deFloatFrac(v-0.5f);
   2622 
   2623 	return (sampleRes[0]*(1.0f-a)*(1.0f-b)) +
   2624 		   (sampleRes[1]*(     a)*(1.0f-b)) +
   2625 		   (sampleRes[2]*(1.0f-a)*(     b)) +
   2626 		   (sampleRes[3]*(     a)*(     b));
   2627 }
   2628 
   2629 static float sampleLevelArrayCubeSeamlessCompare (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
   2630 {
   2631 	bool					magnified	= lod <= sampler.lodThreshold;
   2632 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2633 
   2634 	switch (filterMode)
   2635 	{
   2636 		case Sampler::NEAREST:
   2637 			return sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
   2638 
   2639 		case Sampler::LINEAR:
   2640 		{
   2641 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2642 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2643 				faceAccesses[i] = faces[i][0];
   2644 
   2645 			return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
   2646 		}
   2647 
   2648 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2649 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2650 		{
   2651 			int						maxLevel	= (int)numLevels-1;
   2652 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2653 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2654 
   2655 			if (levelFilter == Sampler::NEAREST)
   2656 				return sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
   2657 			else
   2658 			{
   2659 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2660 
   2661 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2662 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2663 					faceAccesses[i] = faces[i][level];
   2664 
   2665 				return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
   2666 			}
   2667 		}
   2668 
   2669 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2670 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2671 		{
   2672 			int						maxLevel	= (int)numLevels-1;
   2673 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2674 			int						level1		= de::min(maxLevel, level0 + 1);
   2675 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2676 			float					f			= deFloatFrac(lod);
   2677 			float					t0;
   2678 			float					t1;
   2679 
   2680 			if (levelFilter == Sampler::NEAREST)
   2681 			{
   2682 				t0 = sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
   2683 				t1 = sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
   2684 			}
   2685 			else
   2686 			{
   2687 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2688 
   2689 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
   2690 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
   2691 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2692 				{
   2693 					faceAccesses0[i] = faces[i][level0];
   2694 					faceAccesses1[i] = faces[i][level1];
   2695 				}
   2696 
   2697 				t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
   2698 				t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
   2699 			}
   2700 
   2701 			return t0*(1.0f - f) + t1*f;
   2702 		}
   2703 
   2704 		default:
   2705 			DE_ASSERT(DE_FALSE);
   2706 			return 0.0f;
   2707 	}
   2708 }
   2709 
   2710 // Cube map array sampling
   2711 
   2712 static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face)
   2713 {
   2714 	const ConstPixelBufferAccess&	level	= levels[levelNdx];
   2715 	const int						depth	= (slice * 6) + getCubeArrayFaceIndex(face);
   2716 
   2717 	return getSubregion(level, 0, 0, depth, level.getWidth(), level.getHeight(), 1);
   2718 }
   2719 
   2720 static Vec4 sampleCubeArraySeamless (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float s, float t, float lod)
   2721 {
   2722 	const int					faceDepth	= (slice * 6) + getCubeArrayFaceIndex(face);
   2723 	const bool					magnified	= lod <= sampler.lodThreshold;
   2724 	const Sampler::FilterMode	filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2725 
   2726 	switch (filterMode)
   2727 	{
   2728 		case Sampler::NEAREST:
   2729 			return sampleCubeSeamlessNearest(levels[0], sampler, s, t, faceDepth);
   2730 
   2731 		case Sampler::LINEAR:
   2732 		{
   2733 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2734 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2735 				faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
   2736 
   2737 			return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
   2738 		}
   2739 
   2740 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2741 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2742 		{
   2743 			int						maxLevel	= (int)numLevels-1;
   2744 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2745 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2746 
   2747 			if (levelFilter == Sampler::NEAREST)
   2748 				return sampleCubeSeamlessNearest(levels[level], sampler, s, t, faceDepth);
   2749 			else
   2750 			{
   2751 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2752 
   2753 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2754 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2755 					faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
   2756 
   2757 				return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
   2758 			}
   2759 		}
   2760 
   2761 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2762 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2763 		{
   2764 			int						maxLevel	= (int)numLevels-1;
   2765 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2766 			int						level1		= de::min(maxLevel, level0 + 1);
   2767 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2768 			float					f			= deFloatFrac(lod);
   2769 			Vec4					t0;
   2770 			Vec4					t1;
   2771 
   2772 			if (levelFilter == Sampler::NEAREST)
   2773 			{
   2774 				t0 = sampleCubeSeamlessNearest(levels[level0], sampler, s, t, faceDepth);
   2775 				t1 = sampleCubeSeamlessNearest(levels[level1], sampler, s, t, faceDepth);
   2776 			}
   2777 			else
   2778 			{
   2779 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2780 
   2781 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
   2782 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
   2783 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2784 				{
   2785 					faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
   2786 					faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
   2787 				}
   2788 
   2789 				t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, 0);
   2790 				t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, 0);
   2791 			}
   2792 
   2793 			return t0*(1.0f - f) + t1*f;
   2794 		}
   2795 
   2796 		default:
   2797 			DE_ASSERT(DE_FALSE);
   2798 			return Vec4(0.0f);
   2799 	}
   2800 }
   2801 
   2802 static float sampleCubeArraySeamlessCompare (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
   2803 {
   2804 	const int			faceDepth	= (slice * 6) + getCubeArrayFaceIndex(face);
   2805 	const bool			magnified	= lod <= sampler.lodThreshold;
   2806 	Sampler::FilterMode	filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
   2807 
   2808 	switch (filterMode)
   2809 	{
   2810 		case Sampler::NEAREST:
   2811 			return sampleCubeSeamlessNearestCompare(levels[0], sampler, ref, s, t, faceDepth);
   2812 
   2813 		case Sampler::LINEAR:
   2814 		{
   2815 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2816 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2817 				faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
   2818 
   2819 			return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
   2820 		}
   2821 
   2822 		case Sampler::NEAREST_MIPMAP_NEAREST:
   2823 		case Sampler::LINEAR_MIPMAP_NEAREST:
   2824 		{
   2825 			int						maxLevel	= (int)numLevels-1;
   2826 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
   2827 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
   2828 
   2829 			if (levelFilter == Sampler::NEAREST)
   2830 				return sampleCubeSeamlessNearestCompare(levels[level], sampler, ref, s, t, faceDepth);
   2831 			else
   2832 			{
   2833 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2834 
   2835 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   2836 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2837 					faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
   2838 
   2839 				return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
   2840 			}
   2841 		}
   2842 
   2843 		case Sampler::NEAREST_MIPMAP_LINEAR:
   2844 		case Sampler::LINEAR_MIPMAP_LINEAR:
   2845 		{
   2846 			int						maxLevel	= (int)numLevels-1;
   2847 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
   2848 			int						level1		= de::min(maxLevel, level0 + 1);
   2849 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
   2850 			float					f			= deFloatFrac(lod);
   2851 			float					t0;
   2852 			float					t1;
   2853 
   2854 			if (levelFilter == Sampler::NEAREST)
   2855 			{
   2856 				t0 = sampleCubeSeamlessNearestCompare(levels[level0], sampler, ref, s, t, faceDepth);
   2857 				t1 = sampleCubeSeamlessNearestCompare(levels[level1], sampler, ref, s, t, faceDepth);
   2858 			}
   2859 			else
   2860 			{
   2861 				DE_ASSERT(levelFilter == Sampler::LINEAR);
   2862 
   2863 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
   2864 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
   2865 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   2866 				{
   2867 					faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
   2868 					faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
   2869 				}
   2870 
   2871 				t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
   2872 				t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
   2873 			}
   2874 
   2875 			return t0*(1.0f - f) + t1*f;
   2876 		}
   2877 
   2878 		default:
   2879 			DE_ASSERT(DE_FALSE);
   2880 			return 0.0f;
   2881 	}
   2882 }
   2883 
   2884 inline int computeMipPyramidLevels (int size)
   2885 {
   2886 	return deLog2Floor32(size)+1;
   2887 }
   2888 
   2889 inline int computeMipPyramidLevels (int width, int height)
   2890 {
   2891 	return deLog2Floor32(de::max(width, height))+1;
   2892 }
   2893 
   2894 inline int computeMipPyramidLevels (int width, int height, int depth)
   2895 {
   2896 	return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
   2897 }
   2898 
   2899 inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx)
   2900 {
   2901 	return de::max(baseLevelSize >> levelNdx, 1);
   2902 }
   2903 
   2904 // TextureLevelPyramid
   2905 
   2906 TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels)
   2907 	: m_format	(format)
   2908 	, m_data	(numLevels)
   2909 	, m_access	(numLevels)
   2910 {
   2911 }
   2912 
   2913 TextureLevelPyramid::TextureLevelPyramid (const TextureLevelPyramid& other)
   2914 	: m_format	(other.m_format)
   2915 	, m_data	(other.getNumLevels())
   2916 	, m_access	(other.getNumLevels())
   2917 {
   2918 	for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
   2919 	{
   2920 		if (!other.isLevelEmpty(levelNdx))
   2921 		{
   2922 			const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
   2923 
   2924 			m_data[levelNdx] = other.m_data[levelNdx];
   2925 			m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
   2926 		}
   2927 	}
   2928 }
   2929 
   2930 TextureLevelPyramid& TextureLevelPyramid::operator= (const TextureLevelPyramid& other)
   2931 {
   2932 	if (this == &other)
   2933 		return *this;
   2934 
   2935 	m_format = other.m_format;
   2936 	m_data.resize(other.getNumLevels());
   2937 	m_access.resize(other.getNumLevels());
   2938 
   2939 	for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
   2940 	{
   2941 		if (!other.isLevelEmpty(levelNdx))
   2942 		{
   2943 			const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
   2944 
   2945 			m_data[levelNdx] = other.m_data[levelNdx];
   2946 			m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
   2947 		}
   2948 		else if (!isLevelEmpty(levelNdx))
   2949 			clearLevel(levelNdx);
   2950 	}
   2951 
   2952 	return *this;
   2953 }
   2954 
   2955 TextureLevelPyramid::~TextureLevelPyramid (void)
   2956 {
   2957 }
   2958 
   2959 void TextureLevelPyramid::allocLevel (int levelNdx, int width, int height, int depth)
   2960 {
   2961 	const int	size	= m_format.getPixelSize()*width*height*depth;
   2962 
   2963 	DE_ASSERT(isLevelEmpty(levelNdx));
   2964 
   2965 	m_data[levelNdx].setStorage(size);
   2966 	m_access[levelNdx] = PixelBufferAccess(m_format, width, height, depth, m_data[levelNdx].getPtr());
   2967 }
   2968 
   2969 void TextureLevelPyramid::clearLevel (int levelNdx)
   2970 {
   2971 	DE_ASSERT(!isLevelEmpty(levelNdx));
   2972 
   2973 	m_data[levelNdx].clear();
   2974 	m_access[levelNdx] = PixelBufferAccess();
   2975 }
   2976 
   2977 // Texture1D
   2978 
   2979 Texture1D::Texture1D (const TextureFormat& format, int width)
   2980 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width))
   2981 	, m_width				(width)
   2982 	, m_view				(getNumLevels(), getLevels())
   2983 {
   2984 }
   2985 
   2986 Texture1D::Texture1D (const Texture1D& other)
   2987 	: TextureLevelPyramid	(other)
   2988 	, m_width				(other.m_width)
   2989 	, m_view				(getNumLevels(), getLevels())
   2990 {
   2991 }
   2992 
   2993 Texture1D& Texture1D::operator= (const Texture1D& other)
   2994 {
   2995 	if (this == &other)
   2996 		return *this;
   2997 
   2998 	TextureLevelPyramid::operator=(other);
   2999 
   3000 	m_width		= other.m_width;
   3001 	m_view		= Texture1DView(getNumLevels(), getLevels());
   3002 
   3003 	return *this;
   3004 }
   3005 
   3006 Texture1D::~Texture1D (void)
   3007 {
   3008 }
   3009 
   3010 void Texture1D::allocLevel (int levelNdx)
   3011 {
   3012 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
   3013 
   3014 	const int width = getMipPyramidLevelSize(m_width, levelNdx);
   3015 
   3016 	TextureLevelPyramid::allocLevel(levelNdx, width, 1, 1);
   3017 }
   3018 
   3019 // Texture2D
   3020 
   3021 Texture2D::Texture2D (const TextureFormat& format, int width, int height)
   3022 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width, height))
   3023 	, m_width				(width)
   3024 	, m_height				(height)
   3025 	, m_view				(getNumLevels(), getLevels())
   3026 {
   3027 }
   3028 
   3029 Texture2D::Texture2D (const Texture2D& other)
   3030 	: TextureLevelPyramid	(other)
   3031 	, m_width				(other.m_width)
   3032 	, m_height				(other.m_height)
   3033 	, m_view				(getNumLevels(), getLevels())
   3034 {
   3035 }
   3036 
   3037 Texture2D& Texture2D::operator= (const Texture2D& other)
   3038 {
   3039 	if (this == &other)
   3040 		return *this;
   3041 
   3042 	TextureLevelPyramid::operator=(other);
   3043 
   3044 	m_width		= other.m_width;
   3045 	m_height	= other.m_height;
   3046 	m_view		= Texture2DView(getNumLevels(), getLevels());
   3047 
   3048 	return *this;
   3049 }
   3050 
   3051 Texture2D::~Texture2D (void)
   3052 {
   3053 }
   3054 
   3055 void Texture2D::allocLevel (int levelNdx)
   3056 {
   3057 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
   3058 
   3059 	const int	width	= getMipPyramidLevelSize(m_width, levelNdx);
   3060 	const int	height	= getMipPyramidLevelSize(m_height, levelNdx);
   3061 
   3062 	TextureLevelPyramid::allocLevel(levelNdx, width, height, 1);
   3063 }
   3064 
   3065 // TextureCubeView
   3066 
   3067 TextureCubeView::TextureCubeView (void)
   3068 	: m_numLevels(0)
   3069 {
   3070 	for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
   3071 		m_levels[ndx] = DE_NULL;
   3072 }
   3073 
   3074 TextureCubeView::TextureCubeView (int numLevels, const ConstPixelBufferAccess* const (&levels) [CUBEFACE_LAST])
   3075 	: m_numLevels(numLevels)
   3076 {
   3077 	for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
   3078 		m_levels[ndx] = levels[ndx];
   3079 }
   3080 
   3081 tcu::Vec4 TextureCubeView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
   3082 {
   3083 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
   3084 
   3085 	// Computes (face, s, t).
   3086 	const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
   3087 	if (sampler.seamlessCubeMap)
   3088 		return sampleLevelArrayCubeSeamless(m_levels, m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod);
   3089 	else
   3090 		return sampleLevelArray2D(m_levels[coords.face], m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod);
   3091 }
   3092 
   3093 float TextureCubeView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
   3094 {
   3095 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
   3096 
   3097 	// Computes (face, s, t).
   3098 	const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
   3099 	if (sampler.seamlessCubeMap)
   3100 		return sampleLevelArrayCubeSeamlessCompare(m_levels, m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod);
   3101 	else
   3102 		return sampleLevelArray2DCompare(m_levels[coords.face], m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, 0));
   3103 }
   3104 
   3105 Vec4 TextureCubeView::gather (const Sampler& sampler, float s, float t, float r, int componentNdx) const
   3106 {
   3107 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
   3108 
   3109 	ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
   3110 	for (int i = 0; i < (int)CUBEFACE_LAST; i++)
   3111 		faceAccesses[i] = m_levels[i][0];
   3112 
   3113 	const CubeFaceFloatCoords	coords	= getCubeFaceCoords(Vec3(s, t, r));
   3114 	const int					size	= faceAccesses[0].getWidth();
   3115 	// Non-normalized coordinates.
   3116 	float						u		= coords.s;
   3117 	float						v		= coords.t;
   3118 
   3119 	if (sampler.normalizedCoords)
   3120 	{
   3121 		u = unnormalize(sampler.wrapS, coords.s, size);
   3122 		v = unnormalize(sampler.wrapT, coords.t, size);
   3123 	}
   3124 
   3125 	Vec4 sampleColors[4];
   3126 	getCubeLinearSamples(faceAccesses, coords.face, u, v, 0, sampleColors);
   3127 
   3128 	const int	sampleIndices[4] = { 2, 3, 1, 0 }; // \note Gather returns the samples in a non-obvious order.
   3129 	Vec4		result;
   3130 	for (int i = 0; i < 4; i++)
   3131 		result[i] = sampleColors[sampleIndices[i]][componentNdx];
   3132 
   3133 	return result;
   3134 }
   3135 
   3136 Vec4 TextureCubeView::gatherCompare (const Sampler& sampler, float ref, float s, float t, float r) const
   3137 {
   3138 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
   3139 	DE_ASSERT(m_levels[0][0].getFormat().order == TextureFormat::D || m_levels[0][0].getFormat().order == TextureFormat::DS);
   3140 	DE_ASSERT(sampler.compareChannel == 0);
   3141 
   3142 	Sampler noCompareSampler = sampler;
   3143 	noCompareSampler.compare = Sampler::COMPAREMODE_NONE;
   3144 
   3145 	const Vec4 gathered			= gather(noCompareSampler, s, t, r, 0 /* component 0: depth */);
   3146 	const bool isFixedPoint		= isFixedPointDepthTextureFormat(m_levels[0][0].getFormat());
   3147 	Vec4 result;
   3148 	for (int i = 0; i < 4; i++)
   3149 		result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
   3150 
   3151 	return result;
   3152 }
   3153 
   3154 // TextureCube
   3155 
   3156 TextureCube::TextureCube (const TextureFormat& format, int size)
   3157 	: m_format	(format)
   3158 	, m_size	(size)
   3159 {
   3160 	const int						numLevels		= computeMipPyramidLevels(m_size);
   3161 	const ConstPixelBufferAccess*	levels[CUBEFACE_LAST];
   3162 
   3163 	for (int face = 0; face < CUBEFACE_LAST; face++)
   3164 	{
   3165 		m_data[face].resize(numLevels);
   3166 		m_access[face].resize(numLevels);
   3167 		levels[face] = &m_access[face][0];
   3168 	}
   3169 
   3170 	m_view = TextureCubeView(numLevels, levels);
   3171 }
   3172 
   3173 TextureCube::TextureCube (const TextureCube& other)
   3174 	: m_format	(other.m_format)
   3175 	, m_size	(other.m_size)
   3176 {
   3177 	const int						numLevels		= computeMipPyramidLevels(m_size);
   3178 	const ConstPixelBufferAccess*	levels[CUBEFACE_LAST];
   3179 
   3180 	for (int face = 0; face < CUBEFACE_LAST; face++)
   3181 	{
   3182 		m_data[face].resize(numLevels);
   3183 		m_access[face].resize(numLevels);
   3184 		levels[face] = &m_access[face][0];
   3185 	}
   3186 
   3187 	m_view = TextureCubeView(numLevels, levels);
   3188 
   3189 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
   3190 	{
   3191 		for (int face = 0; face < CUBEFACE_LAST; face++)
   3192 		{
   3193 			if (!other.isLevelEmpty((CubeFace)face, levelNdx))
   3194 			{
   3195 				allocLevel((CubeFace)face, levelNdx);
   3196 				copy(getLevelFace(levelNdx, (CubeFace)face),
   3197 					 other.getLevelFace(levelNdx, (CubeFace)face));
   3198 			}
   3199 		}
   3200 	}
   3201 }
   3202 
   3203 TextureCube& TextureCube::operator= (const TextureCube& other)
   3204 {
   3205 	if (this == &other)
   3206 		return *this;
   3207 
   3208 	const int						numLevels		= computeMipPyramidLevels(other.m_size);
   3209 	const ConstPixelBufferAccess*	levels[CUBEFACE_LAST];
   3210 
   3211 	for (int face = 0; face < CUBEFACE_LAST; face++)
   3212 	{
   3213 		m_data[face].resize(numLevels);
   3214 		m_access[face].resize(numLevels);
   3215 		levels[face] = &m_access[face][0];
   3216 	}
   3217 
   3218 	m_format	= other.m_format;
   3219 	m_size		= other.m_size;
   3220 	m_view		= TextureCubeView(numLevels, levels);
   3221 
   3222 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
   3223 	{
   3224 		for (int face = 0; face < CUBEFACE_LAST; face++)
   3225 		{
   3226 			if (!isLevelEmpty((CubeFace)face, levelNdx))
   3227 				clearLevel((CubeFace)face, levelNdx);
   3228 
   3229 			if (!other.isLevelEmpty((CubeFace)face, levelNdx))
   3230 			{
   3231 				allocLevel((CubeFace)face, levelNdx);
   3232 				copy(getLevelFace(levelNdx, (CubeFace)face),
   3233 					 other.getLevelFace(levelNdx, (CubeFace)face));
   3234 			}
   3235 		}
   3236 	}
   3237 
   3238 	return *this;
   3239 }
   3240 
   3241 TextureCube::~TextureCube (void)
   3242 {
   3243 }
   3244 
   3245 void TextureCube::allocLevel (tcu::CubeFace face, int levelNdx)
   3246 {
   3247 	const int	size		= getMipPyramidLevelSize(m_size, levelNdx);
   3248 	const int	dataSize	= m_format.getPixelSize()*size*size;
   3249 	DE_ASSERT(isLevelEmpty(face, levelNdx));
   3250 
   3251 	m_data[face][levelNdx].setStorage(dataSize);
   3252 	m_access[face][levelNdx] = PixelBufferAccess(m_format, size, size, 1, m_data[face][levelNdx].getPtr());
   3253 }
   3254 
   3255 void TextureCube::clearLevel (tcu::CubeFace face, int levelNdx)
   3256 {
   3257 	DE_ASSERT(!isLevelEmpty(face, levelNdx));
   3258 	m_data[face][levelNdx].clear();
   3259 	m_access[face][levelNdx] = PixelBufferAccess();
   3260 }
   3261 
   3262 // Texture1DArrayView
   3263 
   3264 Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
   3265 	: m_numLevels	(numLevels)
   3266 	, m_levels		(levels)
   3267 {
   3268 }
   3269 
   3270 inline int Texture1DArrayView::selectLayer (float r) const
   3271 {
   3272 	DE_ASSERT(m_numLevels > 0 && m_levels);
   3273 	return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getHeight()-1);
   3274 }
   3275 
   3276 Vec4 Texture1DArrayView::sample (const Sampler& sampler, float s, float t, float lod) const
   3277 {
   3278 	return sampleLevelArray1D(m_levels, m_numLevels, sampler, s, selectLayer(t), lod);
   3279 }
   3280 
   3281 Vec4 Texture1DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float lod, deInt32 offset) const
   3282 {
   3283 	return sampleLevelArray1DOffset(m_levels, m_numLevels, sampler, s, lod, IVec2(offset, selectLayer(t)));
   3284 }
   3285 
   3286 float Texture1DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float lod) const
   3287 {
   3288 	return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(0, selectLayer(t)));
   3289 }
   3290 
   3291 float Texture1DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float lod, deInt32 offset) const
   3292 {
   3293 	return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(offset, selectLayer(t)));
   3294 }
   3295 
   3296 // Texture2DArrayView
   3297 
   3298 Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
   3299 	: m_numLevels	(numLevels)
   3300 	, m_levels		(levels)
   3301 {
   3302 }
   3303 
   3304 inline int Texture2DArrayView::selectLayer (float r) const
   3305 {
   3306 	DE_ASSERT(m_numLevels > 0 && m_levels);
   3307 	return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getDepth()-1);
   3308 }
   3309 
   3310 Vec4 Texture2DArrayView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
   3311 {
   3312 	return sampleLevelArray2D(m_levels, m_numLevels, sampler, s, t, selectLayer(r), lod);
   3313 }
   3314 
   3315 float Texture2DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
   3316 {
   3317 	return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(0, 0, selectLayer(r)));
   3318 }
   3319 
   3320 Vec4 Texture2DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float r, float lod, const IVec2& offset) const
   3321 {
   3322 	return sampleLevelArray2DOffset(m_levels, m_numLevels, sampler, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
   3323 }
   3324 
   3325 float Texture2DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float r, float lod, const IVec2& offset) const
   3326 {
   3327 	return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
   3328 }
   3329 
   3330 Vec4 Texture2DArrayView::gatherOffsets (const Sampler& sampler, float s, float t, float r, int componentNdx, const IVec2 (&offsets)[4]) const
   3331 {
   3332 	return gatherArray2DOffsets(m_levels[0], sampler, s, t, selectLayer(r), componentNdx, offsets);
   3333 }
   3334 
   3335 Vec4 Texture2DArrayView::gatherOffsetsCompare (const Sampler& sampler, float ref, float s, float t, float r, const IVec2 (&offsets)[4]) const
   3336 {
   3337 	return gatherArray2DOffsetsCompare(m_levels[0], sampler, ref, s, t, selectLayer(r), offsets);
   3338 }
   3339 
   3340 // Texture1DArray
   3341 
   3342 Texture1DArray::Texture1DArray (const TextureFormat& format, int width, int numLayers)
   3343 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width))
   3344 	, m_width				(width)
   3345 	, m_numLayers			(numLayers)
   3346 	, m_view				(getNumLevels(), getLevels())
   3347 {
   3348 }
   3349 
   3350 Texture1DArray::Texture1DArray (const Texture1DArray& other)
   3351 	: TextureLevelPyramid	(other)
   3352 	, m_width				(other.m_width)
   3353 	, m_numLayers			(other.m_numLayers)
   3354 	, m_view				(getNumLevels(), getLevels())
   3355 {
   3356 }
   3357 
   3358 Texture1DArray& Texture1DArray::operator= (const Texture1DArray& other)
   3359 {
   3360 	if (this == &other)
   3361 		return *this;
   3362 
   3363 	TextureLevelPyramid::operator=(other);
   3364 
   3365 	m_width		= other.m_width;
   3366 	m_numLayers	= other.m_numLayers;
   3367 	m_view		= Texture1DArrayView(getNumLevels(), getLevels());
   3368 
   3369 	return *this;
   3370 }
   3371 
   3372 Texture1DArray::~Texture1DArray (void)
   3373 {
   3374 }
   3375 
   3376 void Texture1DArray::allocLevel (int levelNdx)
   3377 {
   3378 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
   3379 
   3380 	const int width = getMipPyramidLevelSize(m_width, levelNdx);
   3381 
   3382 	TextureLevelPyramid::allocLevel(levelNdx, width, m_numLayers, 1);
   3383 }
   3384 
   3385 // Texture2DArray
   3386 
   3387 Texture2DArray::Texture2DArray (const TextureFormat& format, int width, int height, int numLayers)
   3388 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width, height))
   3389 	, m_width				(width)
   3390 	, m_height				(height)
   3391 	, m_numLayers			(numLayers)
   3392 	, m_view				(getNumLevels(), getLevels())
   3393 {
   3394 }
   3395 
   3396 Texture2DArray::Texture2DArray (const Texture2DArray& other)
   3397 	: TextureLevelPyramid	(other)
   3398 	, m_width				(other.m_width)
   3399 	, m_height				(other.m_height)
   3400 	, m_numLayers			(other.m_numLayers)
   3401 	, m_view				(getNumLevels(), getLevels())
   3402 {
   3403 }
   3404 
   3405 Texture2DArray& Texture2DArray::operator= (const Texture2DArray& other)
   3406 {
   3407 	if (this == &other)
   3408 		return *this;
   3409 
   3410 	TextureLevelPyramid::operator=(other);
   3411 
   3412 	m_width		= other.m_width;
   3413 	m_height	= other.m_height;
   3414 	m_numLayers	= other.m_numLayers;
   3415 	m_view		= Texture2DArrayView(getNumLevels(), getLevels());
   3416 
   3417 	return *this;
   3418 }
   3419 
   3420 Texture2DArray::~Texture2DArray (void)
   3421 {
   3422 }
   3423 
   3424 void Texture2DArray::allocLevel (int levelNdx)
   3425 {
   3426 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
   3427 
   3428 	const int	width	= getMipPyramidLevelSize(m_width,	levelNdx);
   3429 	const int	height	= getMipPyramidLevelSize(m_height,	levelNdx);
   3430 
   3431 	TextureLevelPyramid::allocLevel(levelNdx, width, height, m_numLayers);
   3432 }
   3433 
   3434 // Texture3DView
   3435 
   3436 Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels)
   3437 	: m_numLevels	(numLevels)
   3438 	, m_levels		(levels)
   3439 {
   3440 }
   3441 
   3442 // Texture3D
   3443 
   3444 Texture3D::Texture3D (const TextureFormat& format, int width, int height, int depth)
   3445 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width, height, depth))
   3446 	, m_width				(width)
   3447 	, m_height				(height)
   3448 	, m_depth				(depth)
   3449 	, m_view				(getNumLevels(), getLevels())
   3450 {
   3451 }
   3452 
   3453 Texture3D::Texture3D (const Texture3D& other)
   3454 	: TextureLevelPyramid	(other)
   3455 	, m_width				(other.m_width)
   3456 	, m_height				(other.m_height)
   3457 	, m_depth				(other.m_depth)
   3458 	, m_view				(getNumLevels(), getLevels())
   3459 {
   3460 }
   3461 
   3462 Texture3D& Texture3D::operator= (const Texture3D& other)
   3463 {
   3464 	if (this == &other)
   3465 		return *this;
   3466 
   3467 	TextureLevelPyramid::operator=(other);
   3468 
   3469 	m_width		= other.m_width;
   3470 	m_height	= other.m_height;
   3471 	m_depth		= other.m_depth;
   3472 	m_view		= Texture3DView(getNumLevels(), getLevels());
   3473 
   3474 	return *this;
   3475 }
   3476 
   3477 Texture3D::~Texture3D (void)
   3478 {
   3479 }
   3480 
   3481 void Texture3D::allocLevel (int levelNdx)
   3482 {
   3483 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
   3484 
   3485 	const int width		= getMipPyramidLevelSize(m_width,	levelNdx);
   3486 	const int height	= getMipPyramidLevelSize(m_height,	levelNdx);
   3487 	const int depth		= getMipPyramidLevelSize(m_depth,	levelNdx);
   3488 
   3489 	TextureLevelPyramid::allocLevel(levelNdx, width, height, depth);
   3490 }
   3491 
   3492 // TextureCubeArrayView
   3493 
   3494 TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels)
   3495 	: m_numLevels	(numLevels)
   3496 	, m_levels		(levels)
   3497 {
   3498 }
   3499 
   3500 inline int TextureCubeArrayView::selectLayer (float q) const
   3501 {
   3502 	DE_ASSERT(m_numLevels > 0 && m_levels);
   3503 	DE_ASSERT((m_levels[0].getDepth() % 6) == 0);
   3504 
   3505 	return de::clamp(deFloorFloatToInt32(q + 0.5f), 0, (m_levels[0].getDepth() / 6)-1);
   3506 }
   3507 
   3508 tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const
   3509 {
   3510 	const CubeFaceFloatCoords	coords		= getCubeFaceCoords(Vec3(s, t, r));
   3511 	const int					layer		= selectLayer(q);
   3512 	const int					faceDepth	= (layer * 6) + getCubeArrayFaceIndex(coords.face);
   3513 
   3514 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
   3515 
   3516 	if (sampler.seamlessCubeMap)
   3517 		return sampleCubeArraySeamless(m_levels, m_numLevels, layer, coords.face, sampler, coords.s, coords.t, lod);
   3518 	else
   3519 		return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod);
   3520 }
   3521 
   3522 float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const
   3523 {
   3524 	const CubeFaceFloatCoords	coords		= getCubeFaceCoords(Vec3(s, t, r));
   3525 	const int					layer		= selectLayer(q);
   3526 	const int					faceDepth	= (layer * 6) + getCubeArrayFaceIndex(coords.face);
   3527 
   3528 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
   3529 
   3530 	if (sampler.seamlessCubeMap)
   3531 		return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, layer, coords.face, sampler, ref, coords.s, coords.t, lod);
   3532 	else
   3533 		return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth));
   3534 }
   3535 
   3536 // TextureCubeArray
   3537 
   3538 TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int depth)
   3539 	: TextureLevelPyramid	(format, computeMipPyramidLevels(size))
   3540 	, m_size				(size)
   3541 	, m_depth				(depth)
   3542 	, m_view				(getNumLevels(), getLevels())
   3543 {
   3544 	DE_ASSERT(m_depth % 6 == 0);
   3545 }
   3546 
   3547 TextureCubeArray::TextureCubeArray (const TextureCubeArray& other)
   3548 	: TextureLevelPyramid	(other)
   3549 	, m_size				(other.m_size)
   3550 	, m_depth				(other.m_depth)
   3551 	, m_view				(getNumLevels(), getLevels())
   3552 {
   3553 	DE_ASSERT(m_depth % 6 == 0);
   3554 }
   3555 
   3556 TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
   3557 {
   3558 	if (this == &other)
   3559 		return *this;
   3560 
   3561 	TextureLevelPyramid::operator=(other);
   3562 
   3563 	m_size	= other.m_size;
   3564 	m_depth	= other.m_depth;
   3565 	m_view	= TextureCubeArrayView(getNumLevels(), getLevels());
   3566 
   3567 	DE_ASSERT(m_depth % 6 == 0);
   3568 
   3569 	return *this;
   3570 }
   3571 
   3572 TextureCubeArray::~TextureCubeArray (void)
   3573 {
   3574 }
   3575 
   3576 void TextureCubeArray::allocLevel (int levelNdx)
   3577 {
   3578 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
   3579 
   3580 	const int size = getMipPyramidLevelSize(m_size, levelNdx);
   3581 
   3582 	TextureLevelPyramid::allocLevel(levelNdx, size, size, m_depth);
   3583 }
   3584 
   3585 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order)
   3586 {
   3587 	switch (order)
   3588 	{
   3589 		case TextureFormat::R:					return str << "R";
   3590 		case TextureFormat::A:					return str << "A";
   3591 		case TextureFormat::I:					return str << "I";
   3592 		case TextureFormat::L:					return str << "L";
   3593 		case TextureFormat::LA:					return str << "LA";
   3594 		case TextureFormat::RG:					return str << "RG";
   3595 		case TextureFormat::RA:					return str << "RA";
   3596 		case TextureFormat::RGB:				return str << "RGB";
   3597 		case TextureFormat::RGBA:				return str << "RGBA";
   3598 		case TextureFormat::ARGB:				return str << "ARGB";
   3599 		case TextureFormat::BGRA:				return str << "BGRA";
   3600 		case TextureFormat::CHANNELORDER_LAST:	return str << "CHANNELORDER_LAST";
   3601 		default:								return str << "UNKNOWN(" << (int)order << ")";
   3602 	}
   3603 }
   3604 
   3605 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelType type)
   3606 {
   3607 	switch (type)
   3608 	{
   3609 		case TextureFormat::SNORM_INT8:			return str << "SNORM_INT8";
   3610 		case TextureFormat::SNORM_INT16:		return str << "SNORM_INT16";
   3611 		case TextureFormat::UNORM_INT8:			return str << "UNORM_INT8";
   3612 		case TextureFormat::UNORM_INT16:		return str << "UNORM_INT16";
   3613 		case TextureFormat::UNORM_SHORT_565:	return str << "UNORM_SHORT_565";
   3614 		case TextureFormat::UNORM_SHORT_555:	return str << "UNORM_SHORT_555";
   3615 		case TextureFormat::UNORM_SHORT_4444:	return str << "UNORM_SHORT_4444";
   3616 		case TextureFormat::UNORM_SHORT_5551:	return str << "UNORM_SHORT_5551";
   3617 		case TextureFormat::UNORM_INT_101010:	return str << "UNORM_INT_101010";
   3618 		case TextureFormat::SIGNED_INT8:		return str << "SIGNED_INT8";
   3619 		case TextureFormat::SIGNED_INT16:		return str << "SIGNED_INT16";
   3620 		case TextureFormat::SIGNED_INT32:		return str << "SIGNED_INT32";
   3621 		case TextureFormat::UNSIGNED_INT8:		return str << "UNSIGNED_INT8";
   3622 		case TextureFormat::UNSIGNED_INT16:		return str << "UNSIGNED_INT16";
   3623 		case TextureFormat::UNSIGNED_INT32:		return str << "UNSIGNED_INT32";
   3624 		case TextureFormat::HALF_FLOAT:			return str << "HALF_FLOAT";
   3625 		case TextureFormat::FLOAT:				return str << "FLOAT";
   3626 		case TextureFormat::CHANNELTYPE_LAST:	return str << "CHANNELTYPE_LAST";
   3627 		default:								return str << "UNKNOWN(" << (int)type << ")";
   3628 	}
   3629 }
   3630 
   3631 std::ostream& operator<< (std::ostream& str, CubeFace face)
   3632 {
   3633 	switch (face)
   3634 	{
   3635 		case CUBEFACE_NEGATIVE_X:	return str << "CUBEFACE_NEGATIVE_X";
   3636 		case CUBEFACE_POSITIVE_X:	return str << "CUBEFACE_POSITIVE_X";
   3637 		case CUBEFACE_NEGATIVE_Y:	return str << "CUBEFACE_NEGATIVE_Y";
   3638 		case CUBEFACE_POSITIVE_Y:	return str << "CUBEFACE_POSITIVE_Y";
   3639 		case CUBEFACE_NEGATIVE_Z:	return str << "CUBEFACE_NEGATIVE_Z";
   3640 		case CUBEFACE_POSITIVE_Z:	return str << "CUBEFACE_POSITIVE_Z";
   3641 		case CUBEFACE_LAST:			return str << "CUBEFACE_LAST";
   3642 		default:					return str << "UNKNOWN(" << (int)face << ")";
   3643 	}
   3644 }
   3645 
   3646 std::ostream& operator<< (std::ostream& str, TextureFormat format)
   3647 {
   3648 	return str << format.order << ", " << format.type << "";
   3649 }
   3650 
   3651 std::ostream& operator<< (std::ostream& str, const ConstPixelBufferAccess& access)
   3652 {
   3653 	return str << "format = (" << access.getFormat() << "), size = "
   3654 			   << access.getWidth() << " x " << access.getHeight() << " x " << access.getDepth()
   3655 			   << ", pitch = " << access.getRowPitch() << " / " << access.getSlicePitch();
   3656 }
   3657 
   3658 } // tcu
   3659