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