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