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