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