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