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