tcuTextureUtil.cpp revision 35f093054670f38076b8b347d37a41be90a5ac8c
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 Texture utilities.
22 *//*--------------------------------------------------------------------*/
23
24#include "tcuTextureUtil.hpp"
25#include "tcuVectorUtil.hpp"
26#include "deRandom.hpp"
27#include "deMath.h"
28#include "deMemory.h"
29
30#include <limits>
31
32namespace tcu
33{
34
35static inline float sRGBChannelToLinear (float cs)
36{
37	if (cs <= 0.04045)
38		return cs / 12.92f;
39	else
40		return deFloatPow((cs + 0.055f) / 1.055f, 2.4f);
41}
42
43static inline float linearChannelToSRGB (float cl)
44{
45	if (cl <= 0.0f)
46		return 0.0f;
47	else if (cl < 0.0031308f)
48		return 12.92f*cl;
49	else if (cl < 1.0f)
50		return 1.055f*deFloatPow(cl, 0.41666f) - 0.055f;
51	else
52		return 1.0f;
53}
54
55//! Convert sRGB to linear colorspace
56Vec4 sRGBToLinear (const Vec4& cs)
57{
58	return Vec4(sRGBChannelToLinear(cs[0]),
59				sRGBChannelToLinear(cs[1]),
60				sRGBChannelToLinear(cs[2]),
61				cs[3]);
62}
63
64//! Convert from linear to sRGB colorspace
65Vec4 linearToSRGB (const Vec4& cl)
66{
67	return Vec4(linearChannelToSRGB(cl[0]),
68				linearChannelToSRGB(cl[1]),
69				linearChannelToSRGB(cl[2]),
70				cl[3]);
71}
72
73bool isSRGB (TextureFormat format)
74{
75	return	format.order == TextureFormat::sR	||
76			format.order == TextureFormat::sRG	||
77			format.order == TextureFormat::sRGB	||
78			format.order == TextureFormat::sRGBA;
79}
80
81bool isCombinedDepthStencilType (TextureFormat::ChannelType type)
82{
83	// make sure to update this if type table is updated
84	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
85
86	return	type == TextureFormat::UNSIGNED_INT_24_8 ||
87			type == TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV;
88}
89
90//! Get texture channel class for format
91TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
92{
93	// make sure this table is updated if format table is updated
94	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
95
96	switch (channelType)
97	{
98		case TextureFormat::SNORM_INT8:						return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
99		case TextureFormat::SNORM_INT16:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
100		case TextureFormat::SNORM_INT32:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
101		case TextureFormat::UNORM_INT8:						return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
102		case TextureFormat::UNORM_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
103		case TextureFormat::UNORM_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
104		case TextureFormat::UNORM_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
105		case TextureFormat::UNORM_SHORT_565:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
106		case TextureFormat::UNORM_SHORT_555:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
107		case TextureFormat::UNORM_SHORT_4444:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
108		case TextureFormat::UNORM_SHORT_5551:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
109		case TextureFormat::UNORM_INT_101010:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
110		case TextureFormat::UNORM_INT_1010102_REV:			return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
111		case TextureFormat::UNSIGNED_INT_1010102_REV:		return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
112		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return TEXTURECHANNELCLASS_FLOATING_POINT;
113		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return TEXTURECHANNELCLASS_FLOATING_POINT;
114		case TextureFormat::UNSIGNED_INT_24_8:				return TEXTURECHANNELCLASS_LAST;					//!< packed unorm24-uint8
115		case TextureFormat::SIGNED_INT8:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
116		case TextureFormat::SIGNED_INT16:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
117		case TextureFormat::SIGNED_INT32:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
118		case TextureFormat::UNSIGNED_INT8:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
119		case TextureFormat::UNSIGNED_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
120		case TextureFormat::UNSIGNED_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
121		case TextureFormat::UNSIGNED_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
122		case TextureFormat::HALF_FLOAT:						return TEXTURECHANNELCLASS_FLOATING_POINT;
123		case TextureFormat::FLOAT:							return TEXTURECHANNELCLASS_FLOATING_POINT;
124		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return TEXTURECHANNELCLASS_LAST;					//!< packed float32-pad24-uint8
125		default:											return TEXTURECHANNELCLASS_LAST;
126	}
127}
128
129/*--------------------------------------------------------------------*//*!
130 * \brief Get access to subregion of pixel buffer
131 * \param access	Parent access object
132 * \param x			X offset
133 * \param y			Y offset
134 * \param z			Z offset
135 * \param width		Width
136 * \param height	Height
137 * \param depth		Depth
138 * \return Access object that targets given subregion of parent access object
139 *//*--------------------------------------------------------------------*/
140ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
141{
142	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
143	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
144
145	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
146	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
147
148	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
149	DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
150
151	return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
152								  (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
153}
154
155/*--------------------------------------------------------------------*//*!
156 * \brief Get access to subregion of pixel buffer
157 * \param access	Parent access object
158 * \param x			X offset
159 * \param y			Y offset
160 * \param z			Z offset
161 * \param width		Width
162 * \param height	Height
163 * \param depth		Depth
164 * \return Access object that targets given subregion of parent access object
165 *//*--------------------------------------------------------------------*/
166PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
167{
168	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
169	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
170
171	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
172	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
173
174	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
175	DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
176
177	return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
178							 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
179}
180
181/*--------------------------------------------------------------------*//*!
182 * \brief Get access to subregion of pixel buffer
183 * \param access	Parent access object
184 * \param x			X offset
185 * \param y			Y offset
186 * \param width		Width
187 * \param height	Height
188 * \return Access object that targets given subregion of parent access object
189 *//*--------------------------------------------------------------------*/
190PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
191{
192	return getSubregion(access, x, y, 0, width, height, 1);
193}
194
195/*--------------------------------------------------------------------*//*!
196 * \brief Get access to subregion of pixel buffer
197 * \param access	Parent access object
198 * \param x			X offset
199 * \param y			Y offset
200 * \param width		Width
201 * \param height	Height
202 * \return Access object that targets given subregion of parent access object
203 *//*--------------------------------------------------------------------*/
204ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
205{
206	return getSubregion(access, x, y, 0, width, height, 1);
207}
208
209/*--------------------------------------------------------------------*//*!
210 * \brief Flip rows in Y direction
211 * \param access Access object
212 * \return Modified access object where Y coordinates are reversed
213 *//*--------------------------------------------------------------------*/
214PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
215{
216	const int			rowPitch		= access.getRowPitch();
217	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
218	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
219
220	return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
221}
222
223/*--------------------------------------------------------------------*//*!
224 * \brief Flip rows in Y direction
225 * \param access Access object
226 * \return Modified access object where Y coordinates are reversed
227 *//*--------------------------------------------------------------------*/
228ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
229{
230	const int			rowPitch		= access.getRowPitch();
231	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
232	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
233
234	return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
235}
236
237static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType)
238{
239	// make sure this table is updated if format table is updated
240	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
241
242	float cMin = 0.0f;
243	float cMax = 0.0f;
244
245	switch (channelType)
246	{
247		// Signed normalized formats.
248		case TextureFormat::SNORM_INT8:
249		case TextureFormat::SNORM_INT16:
250		case TextureFormat::SNORM_INT32:					cMin = -1.0f;			cMax = 1.0f;			break;
251
252		// Unsigned normalized formats.
253		case TextureFormat::UNORM_INT8:
254		case TextureFormat::UNORM_INT16:
255		case TextureFormat::UNORM_INT24:
256		case TextureFormat::UNORM_INT32:
257		case TextureFormat::UNORM_SHORT_565:
258		case TextureFormat::UNORM_SHORT_4444:
259		case TextureFormat::UNORM_INT_101010:
260		case TextureFormat::UNORM_INT_1010102_REV:			cMin = 0.0f;			cMax = 1.0f;			break;
261
262		// Misc formats.
263		case TextureFormat::SIGNED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
264		case TextureFormat::SIGNED_INT16:					cMin = -32768.0f;		cMax = 32767.0f;		break;
265		case TextureFormat::SIGNED_INT32:					cMin = -2147483648.0f;	cMax = 2147483647.0f;	break;
266		case TextureFormat::UNSIGNED_INT8:					cMin = 0.0f;			cMax = 255.0f;			break;
267		case TextureFormat::UNSIGNED_INT16:					cMin = 0.0f;			cMax = 65535.0f;		break;
268		case TextureFormat::UNSIGNED_INT24:					cMin = 0.0f;			cMax = 16777215.0f;		break;
269		case TextureFormat::UNSIGNED_INT32:					cMin = 0.0f;			cMax = 4294967295.f;	break;
270		case TextureFormat::HALF_FLOAT:						cMin = -1e3f;			cMax = 1e3f;			break;
271		case TextureFormat::FLOAT:							cMin = -1e5f;			cMax = 1e5f;			break;
272		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	cMin = 0.0f;			cMax = 1e4f;			break;
273		case TextureFormat::UNSIGNED_INT_999_E5_REV:		cMin = 0.0f;			cMax = 1e5f;			break;
274
275		default:
276			DE_ASSERT(false);
277	}
278
279	return Vec2(cMin, cMax);
280}
281
282/*--------------------------------------------------------------------*//*!
283 * \brief Get standard parameters for testing texture format
284 *
285 * Returns TextureFormatInfo that describes good parameters for exercising
286 * given TextureFormat. Parameters include value ranges per channel and
287 * suitable lookup scaling and bias in order to reduce result back to
288 * 0..1 range.
289 *//*--------------------------------------------------------------------*/
290TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
291{
292	// Special cases.
293	if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV))
294		return TextureFormatInfo(Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f),
295								 Vec4(	 1023.0f,		 1023.0f,		 1023.0f,		 3.0f),
296								 Vec4(1.0f/1023.f,	1.0f/1023.0f,	1.0f/1023.0f,	1.0f/3.0f),
297								 Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f));
298	else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
299		return TextureFormatInfo(Vec4(0.0f,	0.0f,	0.0f,	0.0f),
300								 Vec4(1.0f,	1.0f,	1.0f,	0.0f),
301								 Vec4(1.0f,	1.0f,	1.0f,	1.0f),
302								 Vec4(0.0f,	0.0f,	0.0f,	0.0f)); // Depth / stencil formats.
303	else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
304		return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
305								 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
306								 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
307								 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
308
309	const Vec2						cRange		= getChannelValueRange(format.type);
310	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
311	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
312														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
313														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
314														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
315	const float						scale		= 1.0f / (cRange[1] - cRange[0]);
316	const float						bias		= -cRange[0] * scale;
317
318	return TextureFormatInfo(select(cRange[0],	0.0f, chnMask),
319							 select(cRange[1],	0.0f, chnMask),
320							 select(scale,		1.0f, chnMask),
321							 select(bias,		0.0f, chnMask));
322}
323
324static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
325{
326	// make sure this table is updated if format table is updated
327	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
328
329	switch (channelType)
330	{
331		case TextureFormat::SNORM_INT8:						return IVec4(8);
332		case TextureFormat::SNORM_INT16:					return IVec4(16);
333		case TextureFormat::SNORM_INT32:					return IVec4(32);
334		case TextureFormat::UNORM_INT8:						return IVec4(8);
335		case TextureFormat::UNORM_INT16:					return IVec4(16);
336		case TextureFormat::UNORM_INT24:					return IVec4(24);
337		case TextureFormat::UNORM_INT32:					return IVec4(32);
338		case TextureFormat::UNORM_SHORT_565:				return IVec4(5,6,5,0);
339		case TextureFormat::UNORM_SHORT_4444:				return IVec4(4);
340		case TextureFormat::UNORM_SHORT_555:				return IVec4(5,5,5,0);
341		case TextureFormat::UNORM_SHORT_5551:				return IVec4(5,5,5,1);
342		case TextureFormat::UNORM_INT_101010:				return IVec4(10,10,10,0);
343		case TextureFormat::UNORM_INT_1010102_REV:			return IVec4(10,10,10,2);
344		case TextureFormat::SIGNED_INT8:					return IVec4(8);
345		case TextureFormat::SIGNED_INT16:					return IVec4(16);
346		case TextureFormat::SIGNED_INT32:					return IVec4(32);
347		case TextureFormat::UNSIGNED_INT8:					return IVec4(8);
348		case TextureFormat::UNSIGNED_INT16:					return IVec4(16);
349		case TextureFormat::UNSIGNED_INT24:					return IVec4(24);
350		case TextureFormat::UNSIGNED_INT32:					return IVec4(32);
351		case TextureFormat::UNSIGNED_INT_1010102_REV:		return IVec4(10,10,10,2);
352		case TextureFormat::UNSIGNED_INT_24_8:				return IVec4(24,8,0,0);
353		case TextureFormat::HALF_FLOAT:						return IVec4(16);
354		case TextureFormat::FLOAT:							return IVec4(32);
355		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(11,11,10,0);
356		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return IVec4(9,9,9,0);
357		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(32,8,0,0);
358		default:
359			DE_ASSERT(false);
360			return IVec4(0);
361	}
362}
363
364IVec4 getTextureFormatBitDepth (const TextureFormat& format)
365{
366	const IVec4						chnBits		= getChannelBitDepth(format.type);
367	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
368	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
369														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
370														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
371														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
372	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
373														(chnMask[1]) ? ((int)map[1]) : (0),
374														(chnMask[2]) ? ((int)map[2]) : (0),
375														(chnMask[3]) ? ((int)map[3]) : (0));
376
377	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
378}
379
380static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
381{
382	// make sure this table is updated if format table is updated
383	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
384
385	switch (channelType)
386	{
387		case TextureFormat::SNORM_INT8:
388		case TextureFormat::SNORM_INT16:
389		case TextureFormat::SNORM_INT32:
390		case TextureFormat::UNORM_INT8:
391		case TextureFormat::UNORM_INT16:
392		case TextureFormat::UNORM_INT24:
393		case TextureFormat::UNORM_INT32:
394		case TextureFormat::UNORM_SHORT_565:
395		case TextureFormat::UNORM_SHORT_4444:
396		case TextureFormat::UNORM_SHORT_555:
397		case TextureFormat::UNORM_SHORT_5551:
398		case TextureFormat::UNORM_INT_101010:
399		case TextureFormat::UNORM_INT_1010102_REV:
400		case TextureFormat::SIGNED_INT8:
401		case TextureFormat::SIGNED_INT16:
402		case TextureFormat::SIGNED_INT32:
403		case TextureFormat::UNSIGNED_INT8:
404		case TextureFormat::UNSIGNED_INT16:
405		case TextureFormat::UNSIGNED_INT24:
406		case TextureFormat::UNSIGNED_INT32:
407		case TextureFormat::UNSIGNED_INT_1010102_REV:
408		case TextureFormat::UNSIGNED_INT_24_8:
409		case TextureFormat::UNSIGNED_INT_999_E5_REV:
410			return getChannelBitDepth(channelType);
411
412		case TextureFormat::HALF_FLOAT:						return IVec4(10);
413		case TextureFormat::FLOAT:							return IVec4(23);
414		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(6,6,5,0);
415		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(23,8,0,0);
416		default:
417			DE_ASSERT(false);
418			return IVec4(0);
419	}
420}
421
422IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
423{
424	const IVec4						chnBits		= getChannelMantissaBitDepth(format.type);
425	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
426	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
427														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
428														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
429														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
430	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
431														(chnMask[1]) ? ((int)map[1]) : (0),
432														(chnMask[2]) ? ((int)map[2]) : (0),
433														(chnMask[3]) ? ((int)map[3]) : (0));
434
435	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
436}
437
438BVec4 getTextureFormatChannelMask (const TextureFormat& format)
439{
440	const TextureSwizzle::Channel* const map = getChannelReadSwizzle(format.order).components;
441	return BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
442				 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
443				 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
444				 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
445}
446
447static inline float linearInterpolate (float t, float minVal, float maxVal)
448{
449	return minVal + (maxVal - minVal) * t;
450}
451
452static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
453{
454	return a + (b - a) * t;
455}
456
457enum
458{
459	CLEAR_OPTIMIZE_THRESHOLD		= 128,
460	CLEAR_OPTIMIZE_MAX_PIXEL_SIZE	= 8
461};
462
463inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
464{
465	DE_ASSERT(dst.getPixelPitch() == pixelSize); // only tightly packed
466
467	deUint8*	dstPtr	= (deUint8*)dst.getPixelPtr(0, y, z);
468	int			width	= dst.getWidth();
469
470	if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize))
471	{
472		deUint64 val;
473		memcpy(&val, pixel, sizeof(val));
474
475		for (int i = 0; i < width; i++)
476			((deUint64*)dstPtr)[i] = val;
477	}
478	else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize))
479	{
480		deUint32 val;
481		memcpy(&val, pixel, sizeof(val));
482
483		for (int i = 0; i < width; i++)
484			((deUint32*)dstPtr)[i] = val;
485	}
486	else
487	{
488		for (int i = 0; i < width; i++)
489			for (int j = 0; j < pixelSize; j++)
490				dstPtr[i*pixelSize+j] = pixel[j];
491	}
492}
493
494void clear (const PixelBufferAccess& access, const Vec4& color)
495{
496	const int	pixelSize				= access.getFormat().getPixelSize();
497	const int	pixelPitch				= access.getPixelPitch();
498	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
499
500	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
501		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
502	{
503		// Convert to destination format.
504		union
505		{
506			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
507			deUint64	u64; // Forces 64-bit alignment.
508		} pixel;
509		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
510		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
511
512		for (int z = 0; z < access.getDepth(); z++)
513			for (int y = 0; y < access.getHeight(); y++)
514				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
515	}
516	else
517	{
518		for (int z = 0; z < access.getDepth(); z++)
519			for (int y = 0; y < access.getHeight(); y++)
520				for (int x = 0; x < access.getWidth(); x++)
521					access.setPixel(color, x, y, z);
522	}
523}
524
525void clear (const PixelBufferAccess& access, const IVec4& color)
526{
527	const int	pixelSize				= access.getFormat().getPixelSize();
528	const int	pixelPitch				= access.getPixelPitch();
529	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
530
531	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
532		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
533	{
534		// Convert to destination format.
535		union
536		{
537			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
538			deUint64	u64; // Forces 64-bit alignment.
539		} pixel;
540		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
541		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
542
543		for (int z = 0; z < access.getDepth(); z++)
544			for (int y = 0; y < access.getHeight(); y++)
545				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
546	}
547	else
548	{
549		for (int z = 0; z < access.getDepth(); z++)
550			for (int y = 0; y < access.getHeight(); y++)
551				for (int x = 0; x < access.getWidth(); x++)
552					access.setPixel(color, x, y, z);
553	}
554}
555
556void clear (const PixelBufferAccess& access, const UVec4& color)
557{
558	clear(access, color.cast<deInt32>());
559}
560
561void clearDepth (const PixelBufferAccess& access, float depth)
562{
563	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::D);
564
565	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_DEPTH), tcu::Vec4(depth, 0.0f, 0.0f, 0.0f));
566}
567
568void clearStencil (const PixelBufferAccess& access, int stencil)
569{
570	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::S);
571
572	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_STENCIL), tcu::UVec4(stencil, 0u, 0u, 0u));
573}
574
575static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
576{
577	DE_ASSERT(access.getHeight() == 1);
578	for (int x = 0; x < access.getWidth(); x++)
579	{
580		float s = ((float)x + 0.5f) / (float)access.getWidth();
581
582		float r = linearInterpolate(s, minVal.x(), maxVal.x());
583		float g = linearInterpolate(s, minVal.y(), maxVal.y());
584		float b = linearInterpolate(s, minVal.z(), maxVal.z());
585		float a = linearInterpolate(s, minVal.w(), maxVal.w());
586
587		access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
588	}
589}
590
591static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
592{
593	for (int y = 0; y < access.getHeight(); y++)
594	{
595		for (int x = 0; x < access.getWidth(); x++)
596		{
597			float s = ((float)x + 0.5f) / (float)access.getWidth();
598			float t = ((float)y + 0.5f) / (float)access.getHeight();
599
600			float r = linearInterpolate((      s  +       t) *0.5f, minVal.x(), maxVal.x());
601			float g = linearInterpolate((      s  + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
602			float b = linearInterpolate(((1.0f-s) +       t) *0.5f, minVal.z(), maxVal.z());
603			float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
604
605			access.setPixel(tcu::Vec4(r, g, b, a), x, y);
606		}
607	}
608}
609
610static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal)
611{
612	for (int z = 0; z < dst.getDepth(); z++)
613	{
614		for (int y = 0; y < dst.getHeight(); y++)
615		{
616			for (int x = 0; x < dst.getWidth(); x++)
617			{
618				float s = ((float)x + 0.5f) / (float)dst.getWidth();
619				float t = ((float)y + 0.5f) / (float)dst.getHeight();
620				float p = ((float)z + 0.5f) / (float)dst.getDepth();
621
622				float r = linearInterpolate(s,						minVal.x(), maxVal.x());
623				float g = linearInterpolate(t,						minVal.y(), maxVal.y());
624				float b = linearInterpolate(p,						minVal.z(), maxVal.z());
625				float a = linearInterpolate(1.0f - (s+t+p)/3.0f,	minVal.w(), maxVal.w());
626
627				dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
628			}
629		}
630	}
631}
632
633void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
634{
635	if (isCombinedDepthStencilType(access.getFormat().type))
636	{
637		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
638		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
639
640		DE_ASSERT(hasDepth || hasStencil);
641
642		// For combined formats, treat D and S as separate channels
643		if (hasDepth)
644			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal);
645		if (hasStencil)
646			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0));
647	}
648	else
649	{
650		if (access.getHeight() == 1 && access.getDepth() == 1)
651			fillWithComponentGradients1D(access, minVal, maxVal);
652		else if (access.getDepth() == 1)
653			fillWithComponentGradients2D(access, minVal, maxVal);
654		else
655			fillWithComponentGradients3D(access, minVal, maxVal);
656	}
657}
658
659static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
660{
661	for (int x = 0; x < access.getWidth(); x++)
662	{
663		int mx = (x / cellSize) % 2;
664
665		if (mx)
666			access.setPixel(colorB, x, 0);
667		else
668			access.setPixel(colorA, x, 0);
669	}
670}
671
672static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
673{
674	for (int y = 0; y < access.getHeight(); y++)
675	{
676		for (int x = 0; x < access.getWidth(); x++)
677		{
678			int mx = (x / cellSize) % 2;
679			int my = (y / cellSize) % 2;
680
681			if (mx ^ my)
682				access.setPixel(colorB, x, y);
683			else
684				access.setPixel(colorA, x, y);
685		}
686	}
687}
688
689static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
690{
691	for (int z = 0; z < access.getDepth(); z++)
692	{
693		for (int y = 0; y < access.getHeight(); y++)
694		{
695			for (int x = 0; x < access.getWidth(); x++)
696			{
697				int mx = (x / cellSize) % 2;
698				int my = (y / cellSize) % 2;
699				int mz = (z / cellSize) % 2;
700
701				if (mx ^ my ^ mz)
702					access.setPixel(colorB, x, y, z);
703				else
704					access.setPixel(colorA, x, y, z);
705			}
706		}
707	}
708}
709
710void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
711{
712	if (isCombinedDepthStencilType(access.getFormat().type))
713	{
714		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
715		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
716
717		DE_ASSERT(hasDepth || hasStencil);
718
719		// For combined formats, treat D and S as separate channels
720		if (hasDepth)
721			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), colorA, colorB);
722		if (hasStencil)
723			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0));
724	}
725	else
726	{
727		if (access.getHeight() == 1 && access.getDepth() == 1)
728			fillWithGrid1D(access, cellSize, colorA, colorB);
729		else if (access.getDepth() == 1)
730			fillWithGrid2D(access, cellSize, colorA, colorB);
731		else
732			fillWithGrid3D(access, cellSize, colorA, colorB);
733	}
734}
735
736void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
737{
738	for (int y = 0; y < access.getHeight(); y++)
739	{
740		for (int x = 0; x < access.getWidth(); x++)
741		{
742			float s = ((float)x + 0.5f) / (float)access.getWidth();
743			float t = ((float)y + 0.5f) / (float)access.getHeight();
744
745			float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
746			float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
747
748			float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
749			access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
750		}
751	}
752}
753
754void fillWithRGBAQuads (const PixelBufferAccess& dst)
755{
756	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
757	int width	= dst.getWidth();
758	int height	= dst.getHeight();
759	int	left	= width/2;
760	int top		= height/2;
761
762	clear(getSubregion(dst, 0,		0,		0, left,		top,		1),	Vec4(1.0f, 0.0f, 0.0f, 1.0f));
763	clear(getSubregion(dst, left,	0,		0, width-left,	top,		1),	Vec4(0.0f, 1.0f, 0.0f, 1.0f));
764	clear(getSubregion(dst, 0,		top,	0, left,		height-top,	1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
765	clear(getSubregion(dst, left,	top,	0, width-left,	height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
766}
767
768// \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
769void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
770{
771	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
772	std::vector<Vec2>	points(numBalls);
773	de::Random			rnd(seed);
774
775	for (int i = 0; i < numBalls; i++)
776	{
777		float x = rnd.getFloat();
778		float y = rnd.getFloat();
779		points[i] = (Vec2(x, y));
780	}
781
782	for (int y = 0; y < dst.getHeight(); y++)
783	for (int x = 0; x < dst.getWidth(); x++)
784	{
785		Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
786
787		float sum = 0.0f;
788		for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
789		{
790			Vec2	d = p - *i;
791			float	f = 0.01f / (d.x()*d.x() + d.y()*d.y());
792
793			sum += f;
794		}
795
796		dst.setPixel(Vec4(sum), x, y);
797	}
798}
799
800void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src)
801{
802	DE_ASSERT(src.getSize() == dst.getSize());
803
804	const int	width				= dst.getWidth();
805	const int	height				= dst.getHeight();
806	const int	depth				= dst.getDepth();
807
808	const int	srcPixelSize		= src.getFormat().getPixelSize();
809	const int	dstPixelSize		= dst.getFormat().getPixelSize();
810	const int	srcPixelPitch		= src.getPixelPitch();
811	const int	dstPixelPitch		= dst.getPixelPitch();
812	const bool	srcTightlyPacked	= (srcPixelSize == srcPixelPitch);
813	const bool	dstTightlyPacked	= (dstPixelSize == dstPixelPitch);
814
815	const bool	srcHasDepth			= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D);
816	const bool	srcHasStencil		= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S);
817	const bool	dstHasDepth			= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D);
818	const bool	dstHasStencil		= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S);
819
820	if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked)
821	{
822		// Fast-path for matching formats.
823		for (int z = 0; z < depth; z++)
824		for (int y = 0; y < height; y++)
825			deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width);
826	}
827	else if (src.getFormat() == dst.getFormat())
828	{
829		// Bit-exact copy for matching formats.
830		for (int z = 0; z < depth; z++)
831		for (int y = 0; y < height; y++)
832		for (int x = 0; x < width; x++)
833			deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize);
834	}
835	else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil)
836	{
837		DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel
838
839		if (dstHasDepth && srcHasDepth)
840		{
841			for (int z = 0; z < depth; z++)
842			for (int y = 0; y < height; y++)
843			for (int x = 0; x < width; x++)
844				dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z);
845		}
846		else if (dstHasDepth && !srcHasDepth)
847		{
848			// consistency with color copies
849			tcu::clearDepth(dst, 0.0f);
850		}
851
852		if (dstHasStencil && srcHasStencil)
853		{
854			for (int z = 0; z < depth; z++)
855			for (int y = 0; y < height; y++)
856			for (int x = 0; x < width; x++)
857				dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
858		}
859		else if (dstHasStencil && !srcHasStencil)
860		{
861			// consistency with color copies
862			tcu::clearStencil(dst, 0u);
863		}
864	}
865	else
866	{
867		TextureChannelClass		srcClass	= getTextureChannelClass(src.getFormat().type);
868		TextureChannelClass		dstClass	= getTextureChannelClass(dst.getFormat().type);
869		bool					srcIsInt	= srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
870		bool					dstIsInt	= dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
871
872		if (srcIsInt && dstIsInt)
873		{
874			for (int z = 0; z < depth; z++)
875			for (int y = 0; y < height; y++)
876			for (int x = 0; x < width; x++)
877				dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
878		}
879		else
880		{
881			for (int z = 0; z < depth; z++)
882			for (int y = 0; y < height; y++)
883			for (int x = 0; x < width; x++)
884				dst.setPixel(src.getPixel(x, y, z), x, y, z);
885		}
886	}
887}
888
889void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
890{
891	DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
892
893	Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
894					filter, filter, 0.0f, false);
895
896	float sX = (float)src.getWidth() / (float)dst.getWidth();
897	float sY = (float)src.getHeight() / (float)dst.getHeight();
898	float sZ = (float)src.getDepth() / (float)dst.getDepth();
899
900	if (dst.getDepth() == 1 && src.getDepth() == 1)
901	{
902		for (int y = 0; y < dst.getHeight(); y++)
903		for (int x = 0; x < dst.getWidth(); x++)
904			dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y);
905	}
906	else
907	{
908		for (int z = 0; z < dst.getDepth(); z++)
909		for (int y = 0; y < dst.getHeight(); y++)
910		for (int x = 0; x < dst.getWidth(); x++)
911			dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z);
912	}
913}
914
915void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
916{
917	const TextureFormat& format = access.getFormat();
918
919	switch (format.type)
920	{
921		case TextureFormat::UNORM_INT8:
922		case TextureFormat::UNORM_INT16:
923			// Normalized unsigned formats.
924			minVal = Vec4(0.0f);
925			maxVal = Vec4(1.0f);
926			break;
927
928		case TextureFormat::SNORM_INT8:
929		case TextureFormat::SNORM_INT16:
930			// Normalized signed formats.
931			minVal = Vec4(-1.0f);
932			maxVal = Vec4(+1.0f);
933			break;
934
935		default:
936			// \note Samples every 4/8th pixel.
937			minVal = Vec4(std::numeric_limits<float>::max());
938			maxVal = Vec4(std::numeric_limits<float>::min());
939
940			for (int z = 0; z < access.getDepth(); z += 2)
941			{
942				for (int y = 0; y < access.getHeight(); y += 2)
943				{
944					for (int x = 0; x < access.getWidth(); x += 2)
945					{
946						Vec4 p = access.getPixel(x, y, z);
947
948						minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0]));
949						minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1]));
950						minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2]));
951						minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3]));
952
953						maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0]));
954						maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1]));
955						maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2]));
956						maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3]));
957					}
958				}
959			}
960			break;
961	}
962}
963
964void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
965{
966	Vec4 minVal, maxVal;
967	estimatePixelValueRange(access, minVal, maxVal);
968
969	const float eps = 0.0001f;
970
971	for (int c = 0; c < 4; c++)
972	{
973		if (maxVal[c] - minVal[c] < eps)
974		{
975			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
976			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
977		}
978		else
979		{
980			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
981			bias[c]		= 0.0f - minVal[c]*scale[c];
982		}
983	}
984}
985
986int getCubeArrayFaceIndex (CubeFace face)
987{
988	DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
989
990	switch (face)
991	{
992		case CUBEFACE_POSITIVE_X:	return 0;
993		case CUBEFACE_NEGATIVE_X:	return 1;
994		case CUBEFACE_POSITIVE_Y:	return 2;
995		case CUBEFACE_NEGATIVE_Y:	return 3;
996		case CUBEFACE_POSITIVE_Z:	return 4;
997		case CUBEFACE_NEGATIVE_Z:	return 5;
998
999		default:
1000			return -1;
1001	}
1002}
1003
1004deUint32 packRGB999E5 (const tcu::Vec4& color)
1005{
1006	const int	mBits	= 9;
1007	const int	eBits	= 5;
1008	const int	eBias	= 15;
1009	const int	eMax	= (1<<eBits)-1;
1010	const float	maxVal	= (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits);
1011
1012	float	rc		= deFloatClamp(color[0], 0.0f, maxVal);
1013	float	gc		= deFloatClamp(color[1], 0.0f, maxVal);
1014	float	bc		= deFloatClamp(color[2], 0.0f, maxVal);
1015	float	maxc	= de::max(rc, de::max(gc, bc));
1016	int		expp	= de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias;
1017	float	e		= deFloatPow(2.0f, (float)(expp-eBias-mBits));
1018	int		maxs	= deFloorFloatToInt32(maxc / e + 0.5f);
1019
1020	deUint32	exps	= maxs == (1<<mBits) ? expp+1 : expp;
1021	deUint32	rs		= (deUint32)deClamp32(deFloorFloatToInt32(rc / e + 0.5f), 0, (1<<9)-1);
1022	deUint32	gs		= (deUint32)deClamp32(deFloorFloatToInt32(gc / e + 0.5f), 0, (1<<9)-1);
1023	deUint32	bs		= (deUint32)deClamp32(deFloorFloatToInt32(bc / e + 0.5f), 0, (1<<9)-1);
1024
1025	DE_ASSERT((exps & ~((1<<5)-1)) == 0);
1026	DE_ASSERT((rs & ~((1<<9)-1)) == 0);
1027	DE_ASSERT((gs & ~((1<<9)-1)) == 0);
1028	DE_ASSERT((bs & ~((1<<9)-1)) == 0);
1029
1030	return rs | (gs << 9) | (bs << 18) | (exps << 27);
1031}
1032
1033// Sampler utils
1034
1035static const void* addOffset (const void* ptr, int numBytes)
1036{
1037	return (const deUint8*)ptr + numBytes;
1038}
1039
1040static void* addOffset (void* ptr, int numBytes)
1041{
1042	return (deUint8*)ptr + numBytes;
1043}
1044
1045template <typename AccessType>
1046static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode)
1047{
1048	// make sure to update this if type table is updated
1049	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
1050
1051	if (!isCombinedDepthStencilType(baseAccess.getFormat().type))
1052		return baseAccess;
1053	else
1054	{
1055#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
1056		const deUint32 uint32ByteOffsetBits0To8	= 0; //!< least significant byte in the lowest address
1057		const deUint32 uint32ByteOffset8To32	= 1;
1058#else
1059		const deUint32 uint32ByteOffsetBits0To8	= 3; //!< least significant byte in the highest address
1060		const deUint32 uint32ByteOffset8To32	= 0;
1061#endif
1062
1063		// Sampled channel must exist
1064		DE_ASSERT(baseAccess.getFormat().order == TextureFormat::DS ||
1065				  (mode == Sampler::MODE_DEPTH && baseAccess.getFormat().order == TextureFormat::D) ||
1066				  (mode == Sampler::MODE_STENCIL && baseAccess.getFormat().order == TextureFormat::S));
1067
1068		// combined formats have multiple channel classes, detect on sampler settings
1069		switch (baseAccess.getFormat().type)
1070		{
1071			case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1072			{
1073				if (mode == Sampler::MODE_DEPTH)
1074				{
1075					// select the float component
1076					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::FLOAT),
1077									  baseAccess.getSize(),
1078									  baseAccess.getPitch(),
1079									  baseAccess.getDataPtr());
1080				}
1081				else if (mode == Sampler::MODE_STENCIL)
1082				{
1083					// select the uint 8 component
1084					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1085									  baseAccess.getSize(),
1086									  baseAccess.getPitch(),
1087									  addOffset(baseAccess.getDataPtr(), 4 + uint32ByteOffsetBits0To8));
1088				}
1089				else
1090				{
1091					// unknown sampler mode
1092					DE_ASSERT(false);
1093					return AccessType();
1094				}
1095			}
1096
1097			case TextureFormat::UNSIGNED_INT_24_8:
1098			{
1099				if (mode == Sampler::MODE_DEPTH)
1100				{
1101					// select the unorm24 component
1102					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
1103									  baseAccess.getSize(),
1104									  baseAccess.getPitch(),
1105									  addOffset(baseAccess.getDataPtr(), uint32ByteOffset8To32));
1106				}
1107				else if (mode == Sampler::MODE_STENCIL)
1108				{
1109					// select the uint 8 component
1110					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1111									  baseAccess.getSize(),
1112									  baseAccess.getPitch(),
1113									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
1114				}
1115				else
1116				{
1117					// unknown sampler mode
1118					DE_ASSERT(false);
1119					return AccessType();
1120				}
1121			}
1122
1123			default:
1124			{
1125				// unknown combined format
1126				DE_ASSERT(false);
1127				return AccessType();
1128			}
1129		}
1130	}
1131}
1132
1133PixelBufferAccess getEffectiveDepthStencilAccess (const PixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1134{
1135	return toSamplerAccess<PixelBufferAccess>(baseAccess, mode);
1136}
1137
1138ConstPixelBufferAccess getEffectiveDepthStencilAccess (const ConstPixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1139{
1140	return toSamplerAccess<ConstPixelBufferAccess>(baseAccess, mode);
1141}
1142
1143TextureFormat getEffectiveDepthStencilTextureFormat (const TextureFormat& baseFormat, Sampler::DepthStencilMode mode)
1144{
1145	return toSamplerAccess(ConstPixelBufferAccess(baseFormat, IVec3(0, 0, 0), DE_NULL), mode).getFormat();
1146}
1147
1148template <typename ViewType>
1149ViewType getEffectiveTView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1150{
1151	storage.resize(src.getNumLevels());
1152
1153	ViewType view = ViewType(src.getNumLevels(), &storage[0]);
1154
1155	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1156		storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode);
1157
1158	return view;
1159}
1160
1161tcu::TextureCubeView getEffectiveTView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1162{
1163	storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels());
1164
1165	const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] =
1166	{
1167		&storage[0 * src.getNumLevels()],
1168		&storage[1 * src.getNumLevels()],
1169		&storage[2 * src.getNumLevels()],
1170		&storage[3 * src.getNumLevels()],
1171		&storage[4 * src.getNumLevels()],
1172		&storage[5 * src.getNumLevels()],
1173	};
1174
1175	tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs);
1176
1177	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1178	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1179		storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode);
1180
1181	return view;
1182}
1183
1184tcu::Texture1DView getEffectiveTextureView (const tcu::Texture1DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1185{
1186	return getEffectiveTView(src, storage, sampler);
1187}
1188
1189tcu::Texture2DView getEffectiveTextureView (const tcu::Texture2DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1190{
1191	return getEffectiveTView(src, storage, sampler);
1192}
1193
1194tcu::Texture3DView getEffectiveTextureView (const tcu::Texture3DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1195{
1196	return getEffectiveTView(src, storage, sampler);
1197}
1198
1199tcu::Texture1DArrayView getEffectiveTextureView (const tcu::Texture1DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1200{
1201	return getEffectiveTView(src, storage, sampler);
1202}
1203
1204tcu::Texture2DArrayView getEffectiveTextureView (const tcu::Texture2DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1205{
1206	return getEffectiveTView(src, storage, sampler);
1207}
1208
1209tcu::TextureCubeView getEffectiveTextureView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1210{
1211	return getEffectiveTView(src, storage, sampler);
1212}
1213
1214tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1215{
1216	return getEffectiveTView(src, storage, sampler);
1217}
1218
1219//! Returns the effective swizzle of a border color. The effective swizzle is the
1220//! equal to first writing an RGBA color with a write swizzle and then reading
1221//! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
1222static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order)
1223{
1224	// make sure to update these tables when channel orders are updated
1225	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 18);
1226
1227	static const TextureSwizzle INV		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1228	static const TextureSwizzle R		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1229	static const TextureSwizzle A		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
1230	static const TextureSwizzle I		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0	}};
1231	static const TextureSwizzle L		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ONE	}};
1232	static const TextureSwizzle LA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3	}};
1233	static const TextureSwizzle RG		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1234	static const TextureSwizzle RA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
1235	static const TextureSwizzle RGB		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_ONE	}};
1236	static const TextureSwizzle RGBA	= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3	}};
1237	static const TextureSwizzle D		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1238	static const TextureSwizzle S		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1239
1240	const TextureSwizzle* swizzle;
1241
1242	switch (order)
1243	{
1244		case TextureFormat::R:			swizzle = &R;		break;
1245		case TextureFormat::A:			swizzle = &A;		break;
1246		case TextureFormat::I:			swizzle = &I;		break;
1247		case TextureFormat::L:			swizzle = &L;		break;
1248		case TextureFormat::LA:			swizzle = &LA;		break;
1249		case TextureFormat::RG:			swizzle = &RG;		break;
1250		case TextureFormat::RA:			swizzle = &RA;		break;
1251		case TextureFormat::RGB:		swizzle = &RGB;		break;
1252		case TextureFormat::RGBA:		swizzle = &RGBA;	break;
1253		case TextureFormat::ARGB:		swizzle = &RGBA;	break;
1254		case TextureFormat::BGRA:		swizzle = &RGBA;	break;
1255		case TextureFormat::sR:			swizzle = &R;		break;
1256		case TextureFormat::sRG:		swizzle = &RG;		break;
1257		case TextureFormat::sRGB:		swizzle = &RGB;		break;
1258		case TextureFormat::sRGBA:		swizzle = &RGBA;	break;
1259		case TextureFormat::D:			swizzle = &D;		break;
1260		case TextureFormat::S:			swizzle = &S;		break;
1261
1262		case TextureFormat::DS:
1263			DE_ASSERT(false); // combined depth-stencil border color?
1264			swizzle = &INV;
1265			break;
1266
1267		default:
1268			DE_ASSERT(false);
1269			swizzle = &INV;
1270			break;
1271	}
1272
1273#ifdef DE_DEBUG
1274
1275	{
1276		// check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
1277		const TextureSwizzle& readSwizzle	= getChannelReadSwizzle(order);
1278		const TextureSwizzle& writeSwizzle	= getChannelWriteSwizzle(order);
1279
1280		for (int ndx = 0; ndx < 4; ++ndx)
1281		{
1282			TextureSwizzle::Channel writeRead = readSwizzle.components[ndx];
1283			if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE)
1284				writeRead = writeSwizzle.components[(int)writeRead];
1285			DE_ASSERT(writeRead == swizzle->components[ndx]);
1286		}
1287	}
1288
1289#endif
1290
1291	return *swizzle;
1292}
1293
1294static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1295{
1296	return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0),
1297					  (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0),
1298					  (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0),
1299					  (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0));
1300}
1301
1302static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1303{
1304	return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0),
1305					  (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0),
1306					  (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0),
1307					  (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0));
1308}
1309
1310static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits)
1311{
1312	return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0),
1313					  (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0),
1314					  (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0),
1315					  (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0));
1316}
1317
1318static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler)
1319{
1320	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
1321	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1322	const bool						isFloat			= channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1323	const bool						isSigned		= channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1324	const float						valueMin		= (isSigned) ? (-1.0f) : (0.0f);
1325	const float						valueMax		= 1.0f;
1326	Vec4							result;
1327
1328	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
1329			  channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1330			  channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
1331
1332	for (int c = 0; c < 4; c++)
1333	{
1334		const TextureSwizzle::Channel map = channelMap[c];
1335		if (map == TextureSwizzle::CHANNEL_ZERO)
1336			result[c] = 0.0f;
1337		else if (map == TextureSwizzle::CHANNEL_ONE)
1338			result[c] = 1.0f;
1339		else if (isFloat)
1340		{
1341			// floating point values are not clamped
1342			result[c] = sampler.borderColor.getAccess<float>()[(int)map];
1343		}
1344		else
1345		{
1346			// fixed point values are clamped to a representable range
1347			result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax);
1348		}
1349	}
1350
1351	return isSRGB(format) ? sRGBToLinear(result) : result;
1352}
1353
1354static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler)
1355{
1356	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
1357	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1358	const IVec4						channelBits		= getChannelBitDepth(format.type);
1359	const IVec4						valueMin		= getNBitSignedIntegerVec4MinValue(channelBits);
1360	const IVec4						valueMax		= getNBitSignedIntegerVec4MaxValue(channelBits);
1361	IVec4							result;
1362
1363	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
1364	DE_UNREF(channelClass);
1365
1366	for (int c = 0; c < 4; c++)
1367	{
1368		const TextureSwizzle::Channel map = channelMap[c];
1369		if (map == TextureSwizzle::CHANNEL_ZERO)
1370			result[c] = 0;
1371		else if (map == TextureSwizzle::CHANNEL_ONE)
1372			result[c] = 1;
1373		else
1374		{
1375			// integer values are clamped to a representable range
1376			result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]);
1377		}
1378	}
1379
1380	return result;
1381}
1382
1383static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler)
1384{
1385	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
1386	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1387	const IVec4						channelBits		= getChannelBitDepth(format.type);
1388	const UVec4						valueMax		= getNBitUnsignedIntegerVec4MaxValue(channelBits);
1389	UVec4							result;
1390
1391	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
1392	DE_UNREF(channelClass);
1393
1394	for (int c = 0; c < 4; c++)
1395	{
1396		const TextureSwizzle::Channel map = channelMap[c];
1397		if (map == TextureSwizzle::CHANNEL_ZERO)
1398			result[c] = 0;
1399		else if (map == TextureSwizzle::CHANNEL_ONE)
1400			result[c] = 1;
1401		else
1402		{
1403			// integer values are clamped to a representable range
1404			result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]);
1405		}
1406	}
1407
1408	return result;
1409}
1410
1411template <typename ScalarType>
1412tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler)
1413{
1414	const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1415
1416	switch (channelClass)
1417	{
1418		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1419		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1420		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1421			return getTextureBorderColorFloat(format, sampler).cast<ScalarType>();
1422
1423		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1424			return getTextureBorderColorInt(format, sampler).cast<ScalarType>();
1425
1426		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1427			return getTextureBorderColorUint(format, sampler).cast<ScalarType>();
1428
1429		default:
1430			DE_ASSERT(false);
1431			return tcu::Vector<ScalarType, 4>();
1432	}
1433}
1434
1435// instantiation
1436template tcu::Vector<float, 4>		sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1437template tcu::Vector<deInt32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1438template tcu::Vector<deUint32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1439
1440} // tcu
1441