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