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