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 
32 namespace tcu
33 {
34 
sRGBChannelToLinear(float cs)35 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 
43 static const deUint32 s_srgb8Lut[256] =
44 {
45 #include "tcuSRGB8Lut.inl"
46 };
47 
sRGB8ChannelToLinear(deUint32 cs)48 static inline float sRGB8ChannelToLinear (deUint32 cs)
49 {
50 	DE_ASSERT(cs < 256);
51 
52 	// \note This triggers UB, but in practice it doesn't cause any problems
53 	return ((const float*)s_srgb8Lut)[cs];
54 }
55 
56 float linearChannelToSRGB (float cl)
57 {
58 	if (cl <= 0.0f)
59 		return 0.0f;
60 	else if (cl < 0.0031308f)
61 		return 12.92f*cl;
62 	else if (cl < 1.0f)
63 		return 1.055f*deFloatPow(cl, 0.41666f) - 0.055f;
64 	else
65 		return 1.0f;
66 }
67 
68 //! Convert sRGB to linear colorspace
69 Vec4 sRGBToLinear (const Vec4& cs)
70 {
71 	return Vec4(sRGBChannelToLinear(cs[0]),
72 				sRGBChannelToLinear(cs[1]),
73 				sRGBChannelToLinear(cs[2]),
74 				cs[3]);
75 }
76 
77 Vec4 sRGB8ToLinear (const UVec4& cs)
78 {
79 	return Vec4(sRGB8ChannelToLinear(cs[0]),
80 				sRGB8ChannelToLinear(cs[1]),
81 				sRGB8ChannelToLinear(cs[2]),
82 				1.0f);
83 }
84 
85 Vec4 sRGBA8ToLinear (const UVec4& cs)
86 {
87 	return Vec4(sRGB8ChannelToLinear(cs[0]),
88 				sRGB8ChannelToLinear(cs[1]),
89 				sRGB8ChannelToLinear(cs[2]),
90 				(float)cs[3] / 255.0f);
91 }
92 
93 //! Convert from linear to sRGB colorspace
94 Vec4 linearToSRGB (const Vec4& cl)
95 {
96 	return Vec4(linearChannelToSRGB(cl[0]),
97 				linearChannelToSRGB(cl[1]),
98 				linearChannelToSRGB(cl[2]),
99 				cl[3]);
100 }
101 
102 bool isSRGB (TextureFormat format)
103 {
104 	// make sure to update this if type table is updated
105 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
106 
107 	return	format.order == TextureFormat::sR		||
108 			format.order == TextureFormat::sRG		||
109 			format.order == TextureFormat::sRGB		||
110 			format.order == TextureFormat::sRGBA	||
111 			format.order == TextureFormat::sBGR		||
112 			format.order == TextureFormat::sBGRA;
113 }
114 
115 tcu::Vec4 linearToSRGBIfNeeded (const TextureFormat& format, const tcu::Vec4& color)
116 {
117 	return isSRGB(format) ? linearToSRGB(color) : color;
118 }
119 
120 bool isCombinedDepthStencilType (TextureFormat::ChannelType type)
121 {
122 	// make sure to update this if type table is updated
123 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
124 
125 	return	type == TextureFormat::UNSIGNED_INT_16_8_8			||
126 			type == TextureFormat::UNSIGNED_INT_24_8			||
127 			type == TextureFormat::UNSIGNED_INT_24_8_REV		||
128 			type == TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV;
129 }
130 
131 bool hasStencilComponent (TextureFormat::ChannelOrder order)
132 {
133 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
134 
135 	switch (order)
136 	{
137 		case TextureFormat::S:
138 		case TextureFormat::DS:
139 			return true;
140 
141 		default:
142 			return false;
143 	}
144 }
145 
146 bool hasDepthComponent (TextureFormat::ChannelOrder order)
147 {
148 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
149 
150 	switch (order)
151 	{
152 		case TextureFormat::D:
153 		case TextureFormat::DS:
154 			return true;
155 
156 		default:
157 			return false;
158 	}
159 }
160 
161 //! Get texture channel class for format - how the values are stored (not how they are sampled)
162 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
163 {
164 	// make sure this table is updated if format table is updated
165 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
166 
167 	switch (channelType)
168 	{
169 		case TextureFormat::SNORM_INT8:						return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
170 		case TextureFormat::SNORM_INT16:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
171 		case TextureFormat::SNORM_INT32:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
172 		case TextureFormat::UNORM_INT8:						return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
173 		case TextureFormat::UNORM_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
174 		case TextureFormat::UNORM_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
175 		case TextureFormat::UNORM_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
176 		case TextureFormat::UNORM_BYTE_44:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
177 		case TextureFormat::UNORM_SHORT_565:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
178 		case TextureFormat::UNORM_SHORT_555:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
179 		case TextureFormat::UNORM_SHORT_4444:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
180 		case TextureFormat::UNORM_SHORT_5551:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
181 		case TextureFormat::UNORM_SHORT_1555:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
182 		case TextureFormat::UNSIGNED_BYTE_44:				return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
183 		case TextureFormat::UNSIGNED_SHORT_565:				return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
184 		case TextureFormat::UNSIGNED_SHORT_4444:			return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
185 		case TextureFormat::UNSIGNED_SHORT_5551:			return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
186 		case TextureFormat::UNORM_INT_101010:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
187 		case TextureFormat::SNORM_INT_1010102_REV:			return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
188 		case TextureFormat::UNORM_INT_1010102_REV:			return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
189 		case TextureFormat::SIGNED_INT_1010102_REV:			return TEXTURECHANNELCLASS_SIGNED_INTEGER;
190 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
191 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return TEXTURECHANNELCLASS_FLOATING_POINT;
192 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return TEXTURECHANNELCLASS_FLOATING_POINT;
193 		case TextureFormat::UNSIGNED_INT_16_8_8:			return TEXTURECHANNELCLASS_LAST;					//!< packed unorm16-x8-uint8
194 		case TextureFormat::UNSIGNED_INT_24_8:				return TEXTURECHANNELCLASS_LAST;					//!< packed unorm24-uint8
195 		case TextureFormat::UNSIGNED_INT_24_8_REV:			return TEXTURECHANNELCLASS_LAST;					//!< packed unorm24-uint8
196 		case TextureFormat::SIGNED_INT8:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
197 		case TextureFormat::SIGNED_INT16:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
198 		case TextureFormat::SIGNED_INT32:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
199 		case TextureFormat::SIGNED_INT64:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
200 		case TextureFormat::UNSIGNED_INT8:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
201 		case TextureFormat::UNSIGNED_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
202 		case TextureFormat::UNSIGNED_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
203 		case TextureFormat::UNSIGNED_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
204 		case TextureFormat::UNSIGNED_INT64:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
205 		case TextureFormat::HALF_FLOAT:						return TEXTURECHANNELCLASS_FLOATING_POINT;
206 		case TextureFormat::FLOAT:							return TEXTURECHANNELCLASS_FLOATING_POINT;
207 		case TextureFormat::FLOAT64:						return TEXTURECHANNELCLASS_FLOATING_POINT;
208 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return TEXTURECHANNELCLASS_LAST;					//!< packed float32-pad24-uint8
209 		case TextureFormat::UNORM_SHORT_10:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
210 		case TextureFormat::UNORM_SHORT_12:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
211 		case TextureFormat::USCALED_INT8:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
212 		case TextureFormat::USCALED_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
213 		case TextureFormat::SSCALED_INT8:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
214 		case TextureFormat::SSCALED_INT16:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
215 		case TextureFormat::USCALED_INT_1010102_REV:		return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
216 		case TextureFormat::SSCALED_INT_1010102_REV:		return TEXTURECHANNELCLASS_SIGNED_INTEGER;
217 		default:
218 			DE_FATAL("Unknown channel type");
219 			return TEXTURECHANNELCLASS_LAST;
220 	}
221 }
222 
223 bool isAccessValid (TextureFormat format, TextureAccessType type)
224 {
225 	DE_ASSERT(isValid(format));
226 
227 	if (format.order == TextureFormat::DS)
228 	{
229 		// It is never allowed to access combined depth-stencil format with getPixel().
230 		// Instead either getPixDepth() or getPixStencil(), or effective depth- or stencil-
231 		// access must be used.
232 		return false;
233 	}
234 	else if (format.order == TextureFormat::D)
235 		return type == TEXTUREACCESSTYPE_FLOAT;
236 	else if (format.order == TextureFormat::S)
237 		return type == TEXTUREACCESSTYPE_UNSIGNED_INT;
238 	else
239 	{
240 		// A few packed color formats have access type restrictions
241 		if (format.type == TextureFormat::UNSIGNED_INT_11F_11F_10F_REV ||
242 			format.type == TextureFormat::UNSIGNED_INT_999_E5_REV)
243 			return type == TEXTUREACCESSTYPE_FLOAT;
244 		else
245 			return true;
246 	}
247 }
248 
249 /*--------------------------------------------------------------------*//*!
250  * \brief Get access to subregion of pixel buffer
251  * \param access	Parent access object
252  * \param x			X offset
253  * \param y			Y offset
254  * \param z			Z offset
255  * \param width		Width
256  * \param height	Height
257  * \param depth		Depth
258  * \return Access object that targets given subregion of parent access object
259  *//*--------------------------------------------------------------------*/
260 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
261 {
262 	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
263 	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
264 
265 	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
266 	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
267 
268 	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
269 	if (depth != -1)	// Handles case of VK_REMAINING_ARRAY_LAYERS
270 		DE_ASSERT(de::inRange(z + depth, z + 1, access.getDepth()));
271 
272 	return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
273 								  (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
274 }
275 
276 /*--------------------------------------------------------------------*//*!
277  * \brief Get access to subregion of pixel buffer
278  * \param access	Parent access object
279  * \param x			X offset
280  * \param y			Y offset
281  * \param z			Z offset
282  * \param width		Width
283  * \param height	Height
284  * \param depth		Depth
285  * \return Access object that targets given subregion of parent access object
286  *//*--------------------------------------------------------------------*/
287 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
288 {
289 	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
290 	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
291 
292 	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
293 	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
294 
295 	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
296 	if (depth != -1)	// Handles case of VK_REMAINING_ARRAY_LAYERS
297 		DE_ASSERT(de::inRange(z + depth, z + 1, access.getDepth()));
298 
299 	return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
300 							 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
301 }
302 
303 /*--------------------------------------------------------------------*//*!
304  * \brief Get access to subregion of pixel buffer
305  * \param access	Parent access object
306  * \param x			X offset
307  * \param y			Y offset
308  * \param width		Width
309  * \param height	Height
310  * \return Access object that targets given subregion of parent access object
311  *//*--------------------------------------------------------------------*/
312 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
313 {
314 	return getSubregion(access, x, y, 0, width, height, 1);
315 }
316 
317 /*--------------------------------------------------------------------*//*!
318  * \brief Get access to subregion of pixel buffer
319  * \param access	Parent access object
320  * \param x			X offset
321  * \param y			Y offset
322  * \param width		Width
323  * \param height	Height
324  * \return Access object that targets given subregion of parent access object
325  *//*--------------------------------------------------------------------*/
326 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
327 {
328 	return getSubregion(access, x, y, 0, width, height, 1);
329 }
330 
331 /*--------------------------------------------------------------------*//*!
332  * \brief Flip rows in Y direction
333  * \param access Access object
334  * \return Modified access object where Y coordinates are reversed
335  *//*--------------------------------------------------------------------*/
336 PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
337 {
338 	const int			rowPitch		= access.getRowPitch();
339 	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
340 	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
341 
342 	return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
343 }
344 
345 /*--------------------------------------------------------------------*//*!
346  * \brief Flip rows in Y direction
347  * \param access Access object
348  * \return Modified access object where Y coordinates are reversed
349  *//*--------------------------------------------------------------------*/
350 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
351 {
352 	const int			rowPitch		= access.getRowPitch();
353 	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
354 	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
355 
356 	return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
357 }
358 
359 static Vec2 getFloatChannelValueRange (TextureFormat::ChannelType channelType)
360 {
361 	// make sure this table is updated if format table is updated
362 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
363 
364 	float cMin = 0.0f;
365 	float cMax = 0.0f;
366 
367 	switch (channelType)
368 	{
369 		// Signed normalized formats.
370 		case TextureFormat::SNORM_INT8:
371 		case TextureFormat::SNORM_INT16:
372 		case TextureFormat::SNORM_INT32:
373 		case TextureFormat::SNORM_INT_1010102_REV:			cMin = -1.0f;			cMax = 1.0f;			break;
374 
375 		// Unsigned normalized formats.
376 		case TextureFormat::UNORM_INT8:
377 		case TextureFormat::UNORM_INT16:
378 		case TextureFormat::UNORM_INT24:
379 		case TextureFormat::UNORM_INT32:
380 		case TextureFormat::UNORM_BYTE_44:
381 		case TextureFormat::UNORM_SHORT_565:
382 		case TextureFormat::UNORM_SHORT_555:
383 		case TextureFormat::UNORM_SHORT_4444:
384 		case TextureFormat::UNORM_SHORT_5551:
385 		case TextureFormat::UNORM_SHORT_1555:
386 		case TextureFormat::UNORM_INT_101010:
387 		case TextureFormat::UNORM_INT_1010102_REV:
388 		case TextureFormat::UNORM_SHORT_10:
389 		case TextureFormat::UNORM_SHORT_12:					cMin = 0.0f;			cMax = 1.0f;			break;
390 
391 		// Misc formats.
392 		case TextureFormat::SIGNED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
393 		case TextureFormat::SIGNED_INT16:					cMin = -32768.0f;		cMax = 32767.0f;		break;
394 		case TextureFormat::SIGNED_INT32:					cMin = -2147483520.0f;	cMax = 2147483520.0f;	break; // Maximum exactly representable 31-bit integer: (2^24 - 1) * 2^7
395 		case TextureFormat::UNSIGNED_INT8:					cMin = 0.0f;			cMax = 255.0f;			break;
396 		case TextureFormat::UNSIGNED_INT16:					cMin = 0.0f;			cMax = 65535.0f;		break;
397 		case TextureFormat::UNSIGNED_INT24:					cMin = 0.0f;			cMax = 16777215.0f;		break;
398 		case TextureFormat::UNSIGNED_INT32:					cMin = 0.0f;			cMax = 4294967040.f;	break; // Maximum exactly representable 32-bit integer: (2^24 - 1) * 2^8
399 		case TextureFormat::HALF_FLOAT:						cMin = -1e3f;			cMax = 1e3f;			break;
400 		case TextureFormat::FLOAT:							cMin = -1e5f;			cMax = 1e5f;			break;
401 		case TextureFormat::FLOAT64:						cMin = -1e5f;			cMax = 1e5f;			break;
402 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	cMin = 0.0f;			cMax = 1e4f;			break;
403 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		cMin = 0.0f;			cMax = 0.5e5f;			break;
404 		case TextureFormat::UNSIGNED_BYTE_44:				cMin = 0.0f;			cMax = 15.f;			break;
405 		case TextureFormat::UNSIGNED_SHORT_4444:			cMin = 0.0f;			cMax = 15.f;			break;
406 		case TextureFormat::USCALED_INT8:					cMin = 0.0f;			cMax = 255.0f;			break;
407 		case TextureFormat::USCALED_INT16:					cMin = 0.0f;			cMax = 65535.0f;		break;
408 		case TextureFormat::SSCALED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
409 		case TextureFormat::SSCALED_INT16:					cMin = -32768.0f;		cMax = 32767.0f;		break;
410 		case TextureFormat::USCALED_INT_1010102_REV:		cMin = 0.0f;			cMax = 1023.0f;			break;
411 		case TextureFormat::SSCALED_INT_1010102_REV:		cMin = -512.0f;			cMax = 511.0f;			break;
412 
413 		default:
414 			DE_ASSERT(false);
415 	}
416 
417 	return Vec2(cMin, cMax);
418 }
419 
420 /*--------------------------------------------------------------------*//*!
421  * \brief Get standard parameters for testing texture format
422  *
423  * Returns TextureFormatInfo that describes good parameters for exercising
424  * given TextureFormat. Parameters include value ranges per channel and
425  * suitable lookup scaling and bias in order to reduce result back to
426  * 0..1 range.
427  *//*--------------------------------------------------------------------*/
428 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
429 {
430 	// Special cases.
431 	if (format.type == TextureFormat::UNSIGNED_INT_1010102_REV)
432 		return TextureFormatInfo(Vec4(	     0.0f,		    0.0f,		    0.0f,		 0.0f),
433 								 Vec4(	  1023.0f,		 1023.0f,		 1023.0f,		 3.0f),
434 								 Vec4(1.0f/1023.f,	1.0f/1023.0f,	1.0f/1023.0f,	1.0f/3.0f),
435 								 Vec4(	     0.0f,		    0.0f,		    0.0f,		 0.0f));
436 	if (format.type == TextureFormat::SIGNED_INT_1010102_REV)
437 		return TextureFormatInfo(Vec4(	  -512.0f,		 -512.0f,		 -512.0f,		-2.0f),
438 								 Vec4(	   511.0f,		  511.0f,		  511.0f,		 1.0f),
439 								 Vec4(1.0f/1023.f,	1.0f/1023.0f,	1.0f/1023.0f,	1.0f/3.0f),
440 								 Vec4(	     0.5f,		    0.5f,		    0.5f,		 0.5f));
441 	else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
442 		return TextureFormatInfo(Vec4(0.0f,	0.0f,	0.0f,	0.0f),
443 								 Vec4(1.0f,	1.0f,	1.0f,	255.0f),
444 								 Vec4(1.0f,	1.0f,	1.0f,	1.0f),
445 								 Vec4(0.0f,	0.0f,	0.0f,	0.0f)); // Depth / stencil formats.
446 	else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
447 		return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
448 								 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
449 								 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
450 								 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
451 	else if (format.type == TextureFormat::UNSIGNED_SHORT_5551)
452 		return TextureFormatInfo(Vec4(	   0.0f,		  0.0f,		  0.0f,	0.0f),
453 								 Vec4(	  31.0f,		 31.0f,		 31.0f,	1.0f),
454 								 Vec4(1.0f/31.f,	1.0f/31.0f,	1.0f/31.0f,	1.0f),
455 								 Vec4(	   0.0f,		  0.0f,		  0.0f,	0.0f));
456 	else if (format.type == TextureFormat::UNSIGNED_SHORT_565)
457 		return TextureFormatInfo(Vec4(	   0.0f,		  0.0f,		  0.0f,	0.0f),
458 								 Vec4(	  31.0f,		 63.0f,		 31.0f,	0.0f),
459 								 Vec4(1.0f/31.f,	1.0f/63.0f,	1.0f/31.0f,	1.0f),
460 								 Vec4(	   0.0f,		  0.0f,		  0.0f,	0.0f));
461 
462 	const Vec2						cRange		= getFloatChannelValueRange(format.type);
463 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
464 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
465 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
466 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
467 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
468 	const float						scale		= 1.0f / (cRange[1] - cRange[0]);
469 	const float						bias		= -cRange[0] * scale;
470 
471 	return TextureFormatInfo(select(cRange[0],	0.0f, chnMask),
472 							 select(cRange[1],	0.0f, chnMask),
473 							 select(scale,		1.0f, chnMask),
474 							 select(bias,		0.0f, chnMask));
475 }
476 
477 IVec4 getFormatMinIntValue (const TextureFormat& format)
478 {
479 	DE_ASSERT(getTextureChannelClass(format.type) == TEXTURECHANNELCLASS_SIGNED_INTEGER);
480 
481 	switch (format.type)
482 	{
483 		case TextureFormat::SIGNED_INT8:	return IVec4(std::numeric_limits<deInt8>::min());
484 		case TextureFormat::SIGNED_INT16:	return IVec4(std::numeric_limits<deInt16>::min());
485 		case TextureFormat::SIGNED_INT32:	return IVec4(std::numeric_limits<deInt32>::min());
486 
487 		default:
488 			DE_FATAL("Invalid channel type");
489 			return IVec4(0);
490 	}
491 }
492 
493 IVec4 getFormatMaxIntValue (const TextureFormat& format)
494 {
495 	DE_ASSERT(getTextureChannelClass(format.type) == TEXTURECHANNELCLASS_SIGNED_INTEGER);
496 
497 	if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT_1010102_REV)  ||
498 		format == TextureFormat(TextureFormat::BGRA, TextureFormat::SSCALED_INT_1010102_REV) ||
499 		format == TextureFormat(TextureFormat::RGBA, TextureFormat::SSCALED_INT_1010102_REV) ||
500 		format == TextureFormat(TextureFormat::BGRA, TextureFormat::SIGNED_INT_1010102_REV))
501 		return IVec4(511, 511, 511, 1);
502 
503 	switch (format.type)
504 	{
505 		case TextureFormat::SIGNED_INT8:	return IVec4(std::numeric_limits<deInt8>::max());
506 		case TextureFormat::SIGNED_INT16:	return IVec4(std::numeric_limits<deInt16>::max());
507 		case TextureFormat::SIGNED_INT32:	return IVec4(std::numeric_limits<deInt32>::max());
508 
509 		case TextureFormat::SSCALED_INT8:	return IVec4(std::numeric_limits<deInt8>::max());
510 		case TextureFormat::SSCALED_INT16:	return IVec4(std::numeric_limits<deInt16>::max());
511 
512 		default:
513 			DE_FATAL("Invalid channel type");
514 			return IVec4(0);
515 	}
516 }
517 
518 UVec4 getFormatMaxUintValue (const TextureFormat& format)
519 {
520 	DE_ASSERT(getTextureChannelClass(format.type) == TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
521 
522 	if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV) ||
523 		format == TextureFormat(TextureFormat::RGBA, TextureFormat::USCALED_INT_1010102_REV)  ||
524 		format == TextureFormat(TextureFormat::BGRA, TextureFormat::USCALED_INT_1010102_REV)  ||
525 		format == TextureFormat(TextureFormat::BGRA, TextureFormat::UNSIGNED_INT_1010102_REV))
526 		return UVec4(1023u, 1023u, 1023u, 3u);
527 
528 	switch (format.type)
529 	{
530 		case TextureFormat::UNSIGNED_INT8:	return UVec4(std::numeric_limits<deUint8>::max());
531 		case TextureFormat::UNSIGNED_INT16:	return UVec4(std::numeric_limits<deUint16>::max());
532 		case TextureFormat::UNSIGNED_INT24:	return UVec4(0xffffffu);
533 		case TextureFormat::UNSIGNED_INT32:	return UVec4(std::numeric_limits<deUint32>::max());
534 
535 		case TextureFormat::USCALED_INT8:	return UVec4(std::numeric_limits<deUint8>::max());
536 		case TextureFormat::USCALED_INT16:	return UVec4(std::numeric_limits<deUint16>::max());
537 
538 		default:
539 			DE_FATAL("Invalid channel type");
540 			return UVec4(0);
541 	}
542 }
543 
544 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
545 {
546 	// make sure this table is updated if format table is updated
547 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
548 
549 	switch (channelType)
550 	{
551 		case TextureFormat::SNORM_INT8:						return IVec4(8);
552 		case TextureFormat::SNORM_INT16:					return IVec4(16);
553 		case TextureFormat::SNORM_INT32:					return IVec4(32);
554 		case TextureFormat::UNORM_INT8:						return IVec4(8);
555 		case TextureFormat::UNORM_INT16:					return IVec4(16);
556 		case TextureFormat::UNORM_INT24:					return IVec4(24);
557 		case TextureFormat::UNORM_INT32:					return IVec4(32);
558 		case TextureFormat::UNORM_BYTE_44:					return IVec4(4,4,0,0);
559 		case TextureFormat::UNORM_SHORT_565:				return IVec4(5,6,5,0);
560 		case TextureFormat::UNORM_SHORT_4444:				return IVec4(4);
561 		case TextureFormat::UNORM_SHORT_555:				return IVec4(5,5,5,0);
562 		case TextureFormat::UNORM_SHORT_5551:				return IVec4(5,5,5,1);
563 		case TextureFormat::UNORM_SHORT_1555:				return IVec4(1,5,5,5);
564 		case TextureFormat::UNSIGNED_BYTE_44:				return IVec4(4,4,0,0);
565 		case TextureFormat::UNSIGNED_SHORT_565:				return IVec4(5,6,5,0);
566 		case TextureFormat::UNSIGNED_SHORT_4444:			return IVec4(4);
567 		case TextureFormat::UNSIGNED_SHORT_5551:			return IVec4(5,5,5,1);
568 		case TextureFormat::UNORM_INT_101010:				return IVec4(10,10,10,0);
569 		case TextureFormat::SNORM_INT_1010102_REV:			return IVec4(10,10,10,2);
570 		case TextureFormat::UNORM_INT_1010102_REV:			return IVec4(10,10,10,2);
571 		case TextureFormat::SIGNED_INT8:					return IVec4(8);
572 		case TextureFormat::SIGNED_INT16:					return IVec4(16);
573 		case TextureFormat::SIGNED_INT32:					return IVec4(32);
574 		case TextureFormat::SIGNED_INT64:					return IVec4(64);
575 		case TextureFormat::UNSIGNED_INT8:					return IVec4(8);
576 		case TextureFormat::UNSIGNED_INT16:					return IVec4(16);
577 		case TextureFormat::UNSIGNED_INT24:					return IVec4(24);
578 		case TextureFormat::UNSIGNED_INT32:					return IVec4(32);
579 		case TextureFormat::UNSIGNED_INT64:					return IVec4(64);
580 		case TextureFormat::SIGNED_INT_1010102_REV:			return IVec4(10,10,10,2);
581 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return IVec4(10,10,10,2);
582 		case TextureFormat::UNSIGNED_INT_16_8_8:			return IVec4(16,8,0,0);
583 		case TextureFormat::UNSIGNED_INT_24_8:				return IVec4(24,8,0,0);
584 		case TextureFormat::UNSIGNED_INT_24_8_REV:			return IVec4(24,8,0,0);
585 		case TextureFormat::HALF_FLOAT:						return IVec4(16);
586 		case TextureFormat::FLOAT:							return IVec4(32);
587 		case TextureFormat::FLOAT64:						return IVec4(64);
588 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(11,11,10,0);
589 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return IVec4(9,9,9,0);
590 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(32,8,0,0);
591 		case TextureFormat::UNORM_SHORT_10:					return IVec4(10);
592 		case TextureFormat::UNORM_SHORT_12:					return IVec4(12);
593 		case TextureFormat::USCALED_INT8:					return IVec4(8);
594 		case TextureFormat::USCALED_INT16:					return IVec4(16);
595 		case TextureFormat::SSCALED_INT8:					return IVec4(8);
596 		case TextureFormat::SSCALED_INT16:					return IVec4(16);
597 		case TextureFormat::USCALED_INT_1010102_REV:		return IVec4(10,10,10,2);
598 		case TextureFormat::SSCALED_INT_1010102_REV:		return IVec4(10,10,10,2);
599 		default:
600 			DE_ASSERT(false);
601 			return IVec4(0);
602 	}
603 }
604 
605 IVec4 getTextureFormatBitDepth (const TextureFormat& format)
606 {
607 	const IVec4						chnBits		= getChannelBitDepth(format.type);
608 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
609 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
610 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
611 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
612 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
613 	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
614 														(chnMask[1]) ? ((int)map[1]) : (0),
615 														(chnMask[2]) ? ((int)map[2]) : (0),
616 														(chnMask[3]) ? ((int)map[3]) : (0));
617 
618 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
619 }
620 
621 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
622 {
623 	// make sure this table is updated if format table is updated
624 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
625 
626 	switch (channelType)
627 	{
628 		case TextureFormat::SNORM_INT8:
629 		case TextureFormat::SNORM_INT16:
630 		case TextureFormat::SNORM_INT32:
631 		case TextureFormat::UNORM_INT8:
632 		case TextureFormat::UNORM_INT16:
633 		case TextureFormat::UNORM_INT24:
634 		case TextureFormat::UNORM_INT32:
635 		case TextureFormat::UNORM_BYTE_44:
636 		case TextureFormat::UNORM_SHORT_565:
637 		case TextureFormat::UNORM_SHORT_4444:
638 		case TextureFormat::UNORM_SHORT_555:
639 		case TextureFormat::UNORM_SHORT_5551:
640 		case TextureFormat::UNORM_SHORT_1555:
641 		case TextureFormat::UNSIGNED_BYTE_44:
642 		case TextureFormat::UNSIGNED_SHORT_565:
643 		case TextureFormat::UNSIGNED_SHORT_4444:
644 		case TextureFormat::UNSIGNED_SHORT_5551:
645 		case TextureFormat::UNORM_INT_101010:
646 		case TextureFormat::SNORM_INT_1010102_REV:
647 		case TextureFormat::UNORM_INT_1010102_REV:
648 		case TextureFormat::SIGNED_INT8:
649 		case TextureFormat::SIGNED_INT16:
650 		case TextureFormat::SIGNED_INT32:
651 		case TextureFormat::UNSIGNED_INT8:
652 		case TextureFormat::UNSIGNED_INT16:
653 		case TextureFormat::UNSIGNED_INT24:
654 		case TextureFormat::UNSIGNED_INT32:
655 		case TextureFormat::SIGNED_INT_1010102_REV:
656 		case TextureFormat::UNSIGNED_INT_1010102_REV:
657 		case TextureFormat::UNSIGNED_INT_16_8_8:
658 		case TextureFormat::UNSIGNED_INT_24_8:
659 		case TextureFormat::UNSIGNED_INT_24_8_REV:
660 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
661 		case TextureFormat::UNORM_SHORT_10:
662 		case TextureFormat::UNORM_SHORT_12:
663 		case TextureFormat::USCALED_INT8:
664 		case TextureFormat::USCALED_INT16:
665 		case TextureFormat::SSCALED_INT8:
666 		case TextureFormat::SSCALED_INT16:
667 		case TextureFormat::USCALED_INT_1010102_REV:
668 		case TextureFormat::SSCALED_INT_1010102_REV:
669 			return getChannelBitDepth(channelType);
670 
671 		case TextureFormat::HALF_FLOAT:						return IVec4(10);
672 		case TextureFormat::FLOAT:							return IVec4(23);
673 		case TextureFormat::FLOAT64:						return IVec4(52);
674 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(6,6,5,0);
675 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(23,8,0,0);
676 		default:
677 			DE_ASSERT(false);
678 			return IVec4(0);
679 	}
680 }
681 
682 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
683 {
684 	const IVec4						chnBits		= getChannelMantissaBitDepth(format.type);
685 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
686 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
687 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
688 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
689 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
690 	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
691 														(chnMask[1]) ? ((int)map[1]) : (0),
692 														(chnMask[2]) ? ((int)map[2]) : (0),
693 														(chnMask[3]) ? ((int)map[3]) : (0));
694 
695 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
696 }
697 
698 BVec4 getTextureFormatChannelMask (const TextureFormat& format)
699 {
700 	const TextureSwizzle::Channel* const map = getChannelReadSwizzle(format.order).components;
701 	return BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
702 				 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
703 				 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
704 				 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
705 }
706 
707 static inline float linearInterpolate (float t, float minVal, float maxVal)
708 {
709 	return minVal + (maxVal - minVal) * t;
710 }
711 
712 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
713 {
714 	return a + (b - a) * t;
715 }
716 
717 enum
718 {
719 	CLEAR_OPTIMIZE_THRESHOLD		= 128,
720 	CLEAR_OPTIMIZE_MAX_PIXEL_SIZE	= 8
721 };
722 
723 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
724 {
725 	DE_ASSERT(dst.getPixelPitch() == pixelSize); // only tightly packed
726 
727 	deUint8*	dstPtr	= (deUint8*)dst.getPixelPtr(0, y, z);
728 	int			width	= dst.getWidth();
729 
730 	if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize))
731 	{
732 		deUint64 val;
733 		memcpy(&val, pixel, sizeof(val));
734 
735 		for (int i = 0; i < width; i++)
736 			((deUint64*)dstPtr)[i] = val;
737 	}
738 	else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize))
739 	{
740 		deUint32 val;
741 		memcpy(&val, pixel, sizeof(val));
742 
743 		for (int i = 0; i < width; i++)
744 			((deUint32*)dstPtr)[i] = val;
745 	}
746 	else
747 	{
748 		for (int i = 0; i < width; i++)
749 			for (int j = 0; j < pixelSize; j++)
750 				dstPtr[i*pixelSize+j] = pixel[j];
751 	}
752 }
753 
754 void clear (const PixelBufferAccess& access, const Vec4& color)
755 {
756 	const int	pixelSize				= access.getFormat().getPixelSize();
757 	const int	pixelPitch				= access.getPixelPitch();
758 	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
759 
760 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
761 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
762 	{
763 		// Convert to destination format.
764 		union
765 		{
766 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
767 			deUint64	u64; // Forces 64-bit alignment.
768 		} pixel;
769 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
770 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
771 
772 		for (int z = 0; z < access.getDepth(); z++)
773 			for (int y = 0; y < access.getHeight(); y++)
774 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
775 	}
776 	else
777 	{
778 		for (int z = 0; z < access.getDepth(); z++)
779 			for (int y = 0; y < access.getHeight(); y++)
780 				for (int x = 0; x < access.getWidth(); x++)
781 					access.setPixel(color, x, y, z);
782 	}
783 }
784 
785 void clear (const PixelBufferAccess& access, const IVec4& color)
786 {
787 	const int	pixelSize				= access.getFormat().getPixelSize();
788 	const int	pixelPitch				= access.getPixelPitch();
789 	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
790 
791 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
792 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
793 	{
794 		// Convert to destination format.
795 		union
796 		{
797 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
798 			deUint64	u64; // Forces 64-bit alignment.
799 		} pixel;
800 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
801 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
802 
803 		for (int z = 0; z < access.getDepth(); z++)
804 			for (int y = 0; y < access.getHeight(); y++)
805 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
806 	}
807 	else
808 	{
809 		for (int z = 0; z < access.getDepth(); z++)
810 			for (int y = 0; y < access.getHeight(); y++)
811 				for (int x = 0; x < access.getWidth(); x++)
812 					access.setPixel(color, x, y, z);
813 	}
814 }
815 
816 void clear (const PixelBufferAccess& access, const UVec4& color)
817 {
818 	clear(access, color.cast<deInt32>());
819 }
820 
821 void clearDepth (const PixelBufferAccess& access, float depth)
822 {
823 	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::D);
824 
825 	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_DEPTH), tcu::Vec4(depth, 0.0f, 0.0f, 0.0f));
826 }
827 
828 void clearStencil (const PixelBufferAccess& access, int stencil)
829 {
830 	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::S);
831 
832 	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_STENCIL), tcu::UVec4(stencil, 0u, 0u, 0u));
833 }
834 
835 enum GradientStyle
836 {
837 	GRADIENT_STYLE_OLD = 0,
838 	GRADIENT_STYLE_NEW = 1,
839 	GRADIENT_STYLE_PYRAMID = 2
840 };
841 
842 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal, GradientStyle)
843 {
844 	DE_ASSERT(access.getHeight() == 1);
845 	for (int x = 0; x < access.getWidth(); x++)
846 	{
847 		float s = ((float)x + 0.5f) / (float)access.getWidth();
848 
849 		float r = linearInterpolate(s, minVal.x(), maxVal.x());
850 		float g = linearInterpolate(s, minVal.y(), maxVal.y());
851 		float b = linearInterpolate(s, minVal.z(), maxVal.z());
852 		float a = linearInterpolate(s, minVal.w(), maxVal.w());
853 
854 		access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
855 	}
856 }
857 
858 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal, GradientStyle style)
859 {
860 	if (style == GRADIENT_STYLE_PYRAMID)
861 	{
862 		int xedge = deFloorFloatToInt32(float(access.getWidth()) * 0.6f);
863 		int yedge = deFloorFloatToInt32(float(access.getHeight()) * 0.6f);
864 
865 		for (int y = 0; y < access.getHeight(); y++)
866 		{
867 			for (int x = 0; x < access.getWidth(); x++)
868 			{
869 				float s = ((float)x + 0.5f) / (float)access.getWidth();
870 				float t = ((float)y + 0.5f) / (float)access.getHeight();
871 				float coefR = 0.0f;
872 				float coefG = 0.0f;
873 				float coefB = 0.0f;
874 				float coefA = 0.0f;
875 
876 				coefR = (x < xedge) ? s * 0.4f : (1 - s) * 0.6f;
877 				coefG = (x < xedge) ? s * 0.4f : (1 - s) * 0.6f;
878 				coefB = (x < xedge) ? (1.0f - s) * 0.4f : s * 0.6f - 0.2f;
879 				coefA = (x < xedge) ? (1.0f - s) * 0.4f : s * 0.6f - 0.2f;
880 
881 				coefR += (y < yedge) ? t * 0.4f : (1 - t) * 0.6f;
882 				coefG += (y < yedge) ? (1.0f - t) * 0.4f : t * 0.6f - 0.2f;
883 				coefB += (y < yedge) ? t * 0.4f : (1 - t) * 0.6f;
884 				coefA += (y < yedge) ? (1.0f - t) * 0.4f : t * 0.6f - 0.2f;
885 
886 				float r = linearInterpolate(coefR, minVal.x(), maxVal.x());
887 				float g = linearInterpolate(coefG, minVal.y(), maxVal.y());
888 				float b = linearInterpolate(coefB, minVal.z(), maxVal.z());
889 				float a = linearInterpolate(coefA, minVal.w(), maxVal.w());
890 
891 				access.setPixel(tcu::Vec4(r, g, b, a), x, y);
892 			}
893 		}
894 	}
895 	else
896 	{
897 		for (int y = 0; y < access.getHeight(); y++)
898 		{
899 			for (int x = 0; x < access.getWidth(); x++)
900 			{
901 				float s = ((float)x + 0.5f) / (float)access.getWidth();
902 				float t = ((float)y + 0.5f) / (float)access.getHeight();
903 
904 				float r = linearInterpolate((s + t) *0.5f, minVal.x(), maxVal.x());
905 				float g = linearInterpolate((s + (1.0f - t))*0.5f, minVal.y(), maxVal.y());
906 				float b = linearInterpolate(((1.0f - s) + t) *0.5f, minVal.z(), maxVal.z());
907 				float a = linearInterpolate(((1.0f - s) + (1.0f - t))*0.5f, minVal.w(), maxVal.w());
908 
909 				access.setPixel(tcu::Vec4(r, g, b, a), x, y);
910 			}
911 		}
912 	}
913 }
914 
915 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, GradientStyle style)
916 {
917 	for (int z = 0; z < dst.getDepth(); z++)
918 	{
919 		for (int y = 0; y < dst.getHeight(); y++)
920 		{
921 			for (int x = 0; x < dst.getWidth(); x++)
922 			{
923 				float s = ((float)x + 0.5f) / (float)dst.getWidth();
924 				float t = ((float)y + 0.5f) / (float)dst.getHeight();
925 				float p = ((float)z + 0.5f) / (float)dst.getDepth();
926 
927 				float r, g, b, a;
928 
929 				if (style == GRADIENT_STYLE_NEW)
930 				{
931 					// R, G, B and A all depend on every coordinate.
932 					r = linearInterpolate((s+t+p)/3.0f,							minVal.x(), maxVal.x());
933 					g = linearInterpolate((s + (1.0f - (t+p)*0.5f)*2.0f)/3.0f,	minVal.y(), maxVal.y());
934 					b = linearInterpolate(((1.0f - (s+t)*0.5f)*2.0f + p)/3.0f,	minVal.z(), maxVal.z());
935 					a = linearInterpolate(1.0f - (s+t+p)/3.0f,					minVal.w(), maxVal.w());
936 				}
937 				else // GRADIENT_STYLE_OLD
938 				{
939 					// Each of R, G and B only depend on X, Y and Z, respectively.
940 					r = linearInterpolate(s,					minVal.x(), maxVal.x());
941 					g = linearInterpolate(t,					minVal.y(), maxVal.y());
942 					b = linearInterpolate(p,					minVal.z(), maxVal.z());
943 					a = linearInterpolate(1.0f - (s+t+p)/3.0f,	minVal.w(), maxVal.w());
944 				}
945 
946 				dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
947 			}
948 		}
949 	}
950 }
951 
952 void fillWithComponentGradientsStyled (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal, GradientStyle style)
953 {
954 	if (isCombinedDepthStencilType(access.getFormat().type))
955 	{
956 		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
957 		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
958 
959 		DE_ASSERT(hasDepth || hasStencil);
960 
961 		// For combined formats, treat D and S as separate channels
962 		if (hasDepth)
963 			fillWithComponentGradientsStyled(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal, style);
964 		if (hasStencil)
965 			fillWithComponentGradientsStyled(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0), style);
966 	}
967 	else
968 	{
969 		if (access.getHeight() == 1 && access.getDepth() == 1)
970 			fillWithComponentGradients1D(access, minVal, maxVal, style);
971 		else if (access.getDepth() == 1)
972 			fillWithComponentGradients2D(access, minVal, maxVal, style);
973 		else
974 			fillWithComponentGradients3D(access, minVal, maxVal, style);
975 	}
976 }
977 
978 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
979 {
980 	fillWithComponentGradientsStyled(access, minVal, maxVal, GRADIENT_STYLE_OLD);
981 }
982 
983 void fillWithComponentGradients2 (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
984 {
985 	fillWithComponentGradientsStyled(access, minVal, maxVal, GRADIENT_STYLE_NEW);
986 }
987 
988 void fillWithComponentGradients3(const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
989 {
990 	fillWithComponentGradientsStyled(access, minVal, maxVal, GRADIENT_STYLE_PYRAMID);
991 }
992 
993 static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
994 {
995 	for (int x = 0; x < access.getWidth(); x++)
996 	{
997 		int mx = (x / cellSize) % 2;
998 
999 		if (mx)
1000 			access.setPixel(colorB, x, 0);
1001 		else
1002 			access.setPixel(colorA, x, 0);
1003 	}
1004 }
1005 
1006 static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
1007 {
1008 	for (int y = 0; y < access.getHeight(); y++)
1009 	{
1010 		for (int x = 0; x < access.getWidth(); x++)
1011 		{
1012 			int mx = (x / cellSize) % 2;
1013 			int my = (y / cellSize) % 2;
1014 
1015 			if (mx ^ my)
1016 				access.setPixel(colorB, x, y);
1017 			else
1018 				access.setPixel(colorA, x, y);
1019 		}
1020 	}
1021 }
1022 
1023 static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
1024 {
1025 	for (int z = 0; z < access.getDepth(); z++)
1026 	{
1027 		for (int y = 0; y < access.getHeight(); y++)
1028 		{
1029 			for (int x = 0; x < access.getWidth(); x++)
1030 			{
1031 				int mx = (x / cellSize) % 2;
1032 				int my = (y / cellSize) % 2;
1033 				int mz = (z / cellSize) % 2;
1034 
1035 				if (mx ^ my ^ mz)
1036 					access.setPixel(colorB, x, y, z);
1037 				else
1038 					access.setPixel(colorA, x, y, z);
1039 			}
1040 		}
1041 	}
1042 }
1043 
1044 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
1045 {
1046 	if (isCombinedDepthStencilType(access.getFormat().type))
1047 	{
1048 		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
1049 		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
1050 
1051 		DE_ASSERT(hasDepth || hasStencil);
1052 
1053 		// For combined formats, treat D and S as separate channels
1054 		if (hasDepth)
1055 			fillWithGrid(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), cellSize, colorA, colorB);
1056 		if (hasStencil)
1057 			fillWithGrid(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), cellSize, colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0));
1058 	}
1059 	else
1060 	{
1061 		if (access.getHeight() == 1 && access.getDepth() == 1)
1062 			fillWithGrid1D(access, cellSize, colorA, colorB);
1063 		else if (access.getDepth() == 1)
1064 			fillWithGrid2D(access, cellSize, colorA, colorB);
1065 		else
1066 			fillWithGrid3D(access, cellSize, colorA, colorB);
1067 	}
1068 }
1069 
1070 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
1071 {
1072 	for (int y = 0; y < access.getHeight(); y++)
1073 	{
1074 		for (int x = 0; x < access.getWidth(); x++)
1075 		{
1076 			float s = ((float)x + 0.5f) / (float)access.getWidth();
1077 			float t = ((float)y + 0.5f) / (float)access.getHeight();
1078 
1079 			float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
1080 			float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
1081 
1082 			float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
1083 			access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
1084 		}
1085 	}
1086 }
1087 
1088 void fillWithRGBAQuads (const PixelBufferAccess& dst)
1089 {
1090 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
1091 	int width	= dst.getWidth();
1092 	int height	= dst.getHeight();
1093 	int	left	= width/2;
1094 	int top		= height/2;
1095 
1096 	clear(getSubregion(dst, 0,		0,		0, left,		top,		1),	Vec4(1.0f, 0.0f, 0.0f, 1.0f));
1097 	clear(getSubregion(dst, left,	0,		0, width-left,	top,		1),	Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1098 	clear(getSubregion(dst, 0,		top,	0, left,		height-top,	1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
1099 	clear(getSubregion(dst, left,	top,	0, width-left,	height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
1100 }
1101 
1102 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
1103 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
1104 {
1105 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
1106 	std::vector<Vec2>	points(numBalls);
1107 	de::Random			rnd(seed);
1108 
1109 	for (int i = 0; i < numBalls; i++)
1110 	{
1111 		float x = rnd.getFloat();
1112 		float y = rnd.getFloat();
1113 		points[i] = (Vec2(x, y));
1114 	}
1115 
1116 	for (int y = 0; y < dst.getHeight(); y++)
1117 	for (int x = 0; x < dst.getWidth(); x++)
1118 	{
1119 		Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
1120 
1121 		float sum = 0.0f;
1122 		for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
1123 		{
1124 			Vec2	d = p - *i;
1125 			float	f = 0.01f / (d.x()*d.x() + d.y()*d.y());
1126 
1127 			sum += f;
1128 		}
1129 
1130 		dst.setPixel(Vec4(sum), x, y);
1131 	}
1132 }
1133 
1134 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const bool clearUnused)
1135 {
1136 	DE_ASSERT(src.getSize() == dst.getSize());
1137 
1138 	const int	width				= dst.getWidth();
1139 	const int	height				= dst.getHeight();
1140 	const int	depth				= dst.getDepth();
1141 
1142 	const int	srcPixelSize		= src.getFormat().getPixelSize();
1143 	const int	dstPixelSize		= dst.getFormat().getPixelSize();
1144 	const int	srcPixelPitch		= src.getPixelPitch();
1145 	const int	dstPixelPitch		= dst.getPixelPitch();
1146 	const bool	srcTightlyPacked	= (srcPixelSize == srcPixelPitch);
1147 	const bool	dstTightlyPacked	= (dstPixelSize == dstPixelPitch);
1148 
1149 	const bool	srcHasDepth			= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D);
1150 	const bool	srcHasStencil		= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S);
1151 	const bool	dstHasDepth			= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D);
1152 	const bool	dstHasStencil		= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S);
1153 
1154 	if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked)
1155 	{
1156 		// Fast-path for matching formats.
1157 		for (int z = 0; z < depth; z++)
1158 		for (int y = 0; y < height; y++)
1159 			deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width);
1160 	}
1161 	else if (src.getFormat() == dst.getFormat())
1162 	{
1163 		// Bit-exact copy for matching formats.
1164 		for (int z = 0; z < depth; z++)
1165 		for (int y = 0; y < height; y++)
1166 		for (int x = 0; x < width; x++)
1167 			deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize);
1168 	}
1169 	else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil)
1170 	{
1171 		DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel
1172 
1173 		if (dstHasDepth && srcHasDepth)
1174 		{
1175 			for (int z = 0; z < depth; z++)
1176 			for (int y = 0; y < height; y++)
1177 			for (int x = 0; x < width; x++)
1178 				dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z);
1179 		}
1180 		else if (dstHasDepth && !srcHasDepth && clearUnused)
1181 		{
1182 			// consistency with color copies
1183 			tcu::clearDepth(dst, 0.0f);
1184 		}
1185 
1186 		if (dstHasStencil && srcHasStencil)
1187 		{
1188 			for (int z = 0; z < depth; z++)
1189 			for (int y = 0; y < height; y++)
1190 			for (int x = 0; x < width; x++)
1191 				dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
1192 		}
1193 		else if (dstHasStencil && !srcHasStencil && clearUnused)
1194 		{
1195 			// consistency with color copies
1196 			tcu::clearStencil(dst, 0u);
1197 		}
1198 	}
1199 	else
1200 	{
1201 		TextureChannelClass		srcClass	= getTextureChannelClass(src.getFormat().type);
1202 		TextureChannelClass		dstClass	= getTextureChannelClass(dst.getFormat().type);
1203 		bool					srcIsInt	= srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1204 		bool					dstIsInt	= dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1205 
1206 		if (srcIsInt && dstIsInt)
1207 		{
1208 			for (int z = 0; z < depth; z++)
1209 			for (int y = 0; y < height; y++)
1210 			for (int x = 0; x < width; x++)
1211 				dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
1212 		}
1213 		else
1214 		{
1215 			for (int z = 0; z < depth; z++)
1216 			for (int y = 0; y < height; y++)
1217 			for (int x = 0; x < width; x++)
1218 				dst.setPixel(src.getPixel(x, y, z), x, y, z);
1219 		}
1220 	}
1221 }
1222 
1223 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
1224 {
1225 	DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
1226 
1227 	Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
1228 					filter, filter, 0.0f, false);
1229 
1230 	float sX = (float)src.getWidth() / (float)dst.getWidth();
1231 	float sY = (float)src.getHeight() / (float)dst.getHeight();
1232 	float sZ = (float)src.getDepth() / (float)dst.getDepth();
1233 
1234 	if (dst.getDepth() == 1 && src.getDepth() == 1)
1235 	{
1236 		for (int y = 0; y < dst.getHeight(); y++)
1237 		for (int x = 0; x < dst.getWidth(); x++)
1238 			dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample2D(sampler, filter, ((float)x+0.5f)*sX, ((float)y+0.5f)*sY, 0)), x, y);
1239 	}
1240 	else
1241 	{
1242 		for (int z = 0; z < dst.getDepth(); z++)
1243 		for (int y = 0; y < dst.getHeight(); y++)
1244 		for (int x = 0; x < dst.getWidth(); x++)
1245 			dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample3D(sampler, filter, ((float)x+0.5f)*sX, ((float)y+0.5f)*sY, ((float)z+0.5f)*sZ)), x, y, z);
1246 	}
1247 }
1248 
1249 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
1250 {
1251 	const TextureFormat& format = access.getFormat();
1252 
1253 	switch (getTextureChannelClass(format.type))
1254 	{
1255 		case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1256 			// Normalized unsigned formats.
1257 			minVal = Vec4(0.0f);
1258 			maxVal = Vec4(1.0f);
1259 			break;
1260 
1261 		case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1262 			// Normalized signed formats.
1263 			minVal = Vec4(-1.0f);
1264 			maxVal = Vec4(+1.0f);
1265 			break;
1266 
1267 		default:
1268 			// \note Samples every 4/8th pixel.
1269 			minVal = Vec4(std::numeric_limits<float>::max());
1270 			maxVal = Vec4(std::numeric_limits<float>::min());
1271 
1272 			for (int z = 0; z < access.getDepth(); z += 2)
1273 			{
1274 				for (int y = 0; y < access.getHeight(); y += 2)
1275 				{
1276 					for (int x = 0; x < access.getWidth(); x += 2)
1277 					{
1278 						Vec4 p = access.getPixel(x, y, z);
1279 
1280 						minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0]));
1281 						minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1]));
1282 						minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2]));
1283 						minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3]));
1284 
1285 						maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0]));
1286 						maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1]));
1287 						maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2]));
1288 						maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3]));
1289 					}
1290 				}
1291 			}
1292 			break;
1293 	}
1294 }
1295 
1296 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
1297 {
1298 	Vec4 minVal, maxVal;
1299 	estimatePixelValueRange(access, minVal, maxVal);
1300 
1301 	const float eps = 0.0001f;
1302 
1303 	for (int c = 0; c < 4; c++)
1304 	{
1305 		if (maxVal[c] - minVal[c] < eps)
1306 		{
1307 			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
1308 			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
1309 		}
1310 		else
1311 		{
1312 			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
1313 			bias[c]		= 0.0f - minVal[c]*scale[c];
1314 		}
1315 	}
1316 }
1317 
1318 int getCubeArrayFaceIndex (CubeFace face)
1319 {
1320 	DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
1321 
1322 	switch (face)
1323 	{
1324 		case CUBEFACE_POSITIVE_X:	return 0;
1325 		case CUBEFACE_NEGATIVE_X:	return 1;
1326 		case CUBEFACE_POSITIVE_Y:	return 2;
1327 		case CUBEFACE_NEGATIVE_Y:	return 3;
1328 		case CUBEFACE_POSITIVE_Z:	return 4;
1329 		case CUBEFACE_NEGATIVE_Z:	return 5;
1330 
1331 		default:
1332 			return -1;
1333 	}
1334 }
1335 
1336 deUint32 packRGB999E5 (const tcu::Vec4& color)
1337 {
1338 	const int	mBits	= 9;
1339 	const int	eBits	= 5;
1340 	const int	eBias	= 15;
1341 	const int	eMax	= (1<<eBits)-1;
1342 	const float	maxVal	= (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits);
1343 
1344 	float	rc		= deFloatClamp(color[0], 0.0f, maxVal);
1345 	float	gc		= deFloatClamp(color[1], 0.0f, maxVal);
1346 	float	bc		= deFloatClamp(color[2], 0.0f, maxVal);
1347 	float	maxc	= de::max(rc, de::max(gc, bc));
1348 	float	log2c	= deFloatLog2(maxc);
1349 	deInt32	floorc	= deIsInf(log2c) ? std::numeric_limits<deInt32>::min() : deFloorFloatToInt32(log2c);
1350 	int		exps	= de::max(-eBias - 1, floorc) + 1 + eBias;
1351 	float	e		= deFloatPow(2.0f, (float)(exps-eBias-mBits));
1352 	int		maxs	= deFloorFloatToInt32(maxc / e + 0.5f);
1353 
1354 	if (maxs == (1<<mBits))
1355 	{
1356 		exps++;
1357 		e *= 2.0f;
1358 	}
1359 
1360 	deUint32 rs = (deUint32)deFloorFloatToInt32(rc / e + 0.5f);
1361 	deUint32 gs = (deUint32)deFloorFloatToInt32(gc / e + 0.5f);
1362 	deUint32 bs = (deUint32)deFloorFloatToInt32(bc / e + 0.5f);
1363 
1364 	DE_ASSERT((exps & ~((1<<5)-1)) == 0);
1365 	DE_ASSERT((rs & ~((1<<9)-1)) == 0);
1366 	DE_ASSERT((gs & ~((1<<9)-1)) == 0);
1367 	DE_ASSERT((bs & ~((1<<9)-1)) == 0);
1368 
1369 	return rs | (gs << 9) | (bs << 18) | (exps << 27);
1370 }
1371 
1372 // Sampler utils
1373 
1374 static const void* addOffset (const void* ptr, int numBytes)
1375 {
1376 	return (const deUint8*)ptr + numBytes;
1377 }
1378 
1379 static void* addOffset (void* ptr, int numBytes)
1380 {
1381 	return (deUint8*)ptr + numBytes;
1382 }
1383 
1384 template <typename AccessType>
1385 static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode)
1386 {
1387 	// make sure to update this if type table is updated
1388 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
1389 
1390 	if (!isCombinedDepthStencilType(baseAccess.getFormat().type))
1391 		return baseAccess;
1392 	else
1393 	{
1394 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
1395 		const deUint32 uint32ByteOffsetBits0To8		= 0; //!< least significant byte in the lowest address
1396 		const deUint32 uint32ByteOffsetBits0To24	= 0;
1397 		const deUint32 uint32ByteOffsetBits8To32	= 1;
1398 		const deUint32 uint32ByteOffsetBits16To32	= 2;
1399 		const deUint32 uint32ByteOffsetBits24To32	= 3;
1400 #else
1401 		const deUint32 uint32ByteOffsetBits0To8		= 3; //!< least significant byte in the highest address
1402 		const deUint32 uint32ByteOffsetBits0To24	= 1;
1403 		const deUint32 uint32ByteOffsetBits8To32	= 0;
1404 		const deUint32 uint32ByteOffsetBits16To32	= 0;
1405 		const deUint32 uint32ByteOffsetBits24To32	= 0;
1406 #endif
1407 
1408 		// Sampled channel must exist
1409 		DE_ASSERT(baseAccess.getFormat().order == TextureFormat::DS ||
1410 				  (mode == Sampler::MODE_DEPTH && baseAccess.getFormat().order == TextureFormat::D) ||
1411 				  (mode == Sampler::MODE_STENCIL && baseAccess.getFormat().order == TextureFormat::S));
1412 
1413 		// combined formats have multiple channel classes, detect on sampler settings
1414 		switch (baseAccess.getFormat().type)
1415 		{
1416 			case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1417 			{
1418 				if (mode == Sampler::MODE_DEPTH)
1419 				{
1420 					// select the float component
1421 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::FLOAT),
1422 									  baseAccess.getSize(),
1423 									  baseAccess.getPitch(),
1424 									  baseAccess.getDataPtr());
1425 				}
1426 				else if (mode == Sampler::MODE_STENCIL)
1427 				{
1428 					// select the uint 8 component
1429 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1430 									  baseAccess.getSize(),
1431 									  baseAccess.getPitch(),
1432 									  addOffset(baseAccess.getDataPtr(), 4 + uint32ByteOffsetBits0To8));
1433 				}
1434 				else
1435 				{
1436 					// unknown sampler mode
1437 					DE_ASSERT(false);
1438 					return AccessType();
1439 				}
1440 			}
1441 
1442 			case TextureFormat::UNSIGNED_INT_16_8_8:
1443 			{
1444 				if (mode == Sampler::MODE_DEPTH)
1445 				{
1446 					// select the unorm16 component
1447 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT16),
1448 									  baseAccess.getSize(),
1449 									  baseAccess.getPitch(),
1450 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits16To32));
1451 				}
1452 				else if (mode == Sampler::MODE_STENCIL)
1453 				{
1454 					// select the uint 8 component
1455 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1456 									  baseAccess.getSize(),
1457 									  baseAccess.getPitch(),
1458 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
1459 				}
1460 				else
1461 				{
1462 					// unknown sampler mode
1463 					DE_ASSERT(false);
1464 					return AccessType();
1465 				}
1466 			}
1467 
1468 			case TextureFormat::UNSIGNED_INT_24_8:
1469 			{
1470 				if (mode == Sampler::MODE_DEPTH)
1471 				{
1472 					// select the unorm24 component
1473 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
1474 									  baseAccess.getSize(),
1475 									  baseAccess.getPitch(),
1476 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits8To32));
1477 				}
1478 				else if (mode == Sampler::MODE_STENCIL)
1479 				{
1480 					// select the uint 8 component
1481 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1482 									  baseAccess.getSize(),
1483 									  baseAccess.getPitch(),
1484 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
1485 				}
1486 				else
1487 				{
1488 					// unknown sampler mode
1489 					DE_ASSERT(false);
1490 					return AccessType();
1491 				}
1492 			}
1493 
1494 			case TextureFormat::UNSIGNED_INT_24_8_REV:
1495 			{
1496 				if (mode == Sampler::MODE_DEPTH)
1497 				{
1498 					// select the unorm24 component
1499 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
1500 									  baseAccess.getSize(),
1501 									  baseAccess.getPitch(),
1502 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To24));
1503 				}
1504 				else if (mode == Sampler::MODE_STENCIL)
1505 				{
1506 					// select the uint 8 component
1507 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1508 									  baseAccess.getSize(),
1509 									  baseAccess.getPitch(),
1510 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits24To32));
1511 				}
1512 				else
1513 				{
1514 					// unknown sampler mode
1515 					DE_ASSERT(false);
1516 					return AccessType();
1517 				}
1518 			}
1519 
1520 			default:
1521 			{
1522 				// unknown combined format
1523 				DE_ASSERT(false);
1524 				return AccessType();
1525 			}
1526 		}
1527 	}
1528 }
1529 
1530 PixelBufferAccess getEffectiveDepthStencilAccess (const PixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1531 {
1532 	return toSamplerAccess<PixelBufferAccess>(baseAccess, mode);
1533 }
1534 
1535 ConstPixelBufferAccess getEffectiveDepthStencilAccess (const ConstPixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1536 {
1537 	return toSamplerAccess<ConstPixelBufferAccess>(baseAccess, mode);
1538 }
1539 
1540 TextureFormat getEffectiveDepthStencilTextureFormat (const TextureFormat& baseFormat, Sampler::DepthStencilMode mode)
1541 {
1542 	return toSamplerAccess(ConstPixelBufferAccess(baseFormat, IVec3(0, 0, 0), DE_NULL), mode).getFormat();
1543 }
1544 
1545 template <typename ViewType>
1546 ViewType getEffectiveTView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1547 {
1548 	storage.resize(src.getNumLevels());
1549 
1550 	ViewType view = ViewType(src.getNumLevels(), &storage[0], src.isES2(), src.getImageViewMinLodParams());
1551 
1552 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1553 		storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode);
1554 
1555 	return view;
1556 }
1557 
1558 tcu::TextureCubeView getEffectiveTView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1559 {
1560 	storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels());
1561 
1562 	const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] =
1563 	{
1564 		&storage[0 * src.getNumLevels()],
1565 		&storage[1 * src.getNumLevels()],
1566 		&storage[2 * src.getNumLevels()],
1567 		&storage[3 * src.getNumLevels()],
1568 		&storage[4 * src.getNumLevels()],
1569 		&storage[5 * src.getNumLevels()],
1570 	};
1571 
1572 	tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs, false, src.getImageViewMinLodParams());
1573 
1574 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1575 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1576 		storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode);
1577 
1578 	return view;
1579 }
1580 
1581 tcu::Texture1DView getEffectiveTextureView (const tcu::Texture1DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1582 {
1583 	return getEffectiveTView(src, storage, sampler);
1584 }
1585 
1586 tcu::Texture2DView getEffectiveTextureView (const tcu::Texture2DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1587 {
1588 	return getEffectiveTView(src, storage, sampler);
1589 }
1590 
1591 tcu::Texture3DView getEffectiveTextureView (const tcu::Texture3DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1592 {
1593 	return getEffectiveTView(src, storage, sampler);
1594 }
1595 
1596 tcu::Texture1DArrayView getEffectiveTextureView (const tcu::Texture1DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1597 {
1598 	return getEffectiveTView(src, storage, sampler);
1599 }
1600 
1601 tcu::Texture2DArrayView getEffectiveTextureView (const tcu::Texture2DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1602 {
1603 	return getEffectiveTView(src, storage, sampler);
1604 }
1605 
1606 tcu::TextureCubeView getEffectiveTextureView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1607 {
1608 	return getEffectiveTView(src, storage, sampler);
1609 }
1610 
1611 tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1612 {
1613 	return getEffectiveTView(src, storage, sampler);
1614 }
1615 
1616 //! Returns the effective swizzle of a border color. The effective swizzle is the
1617 //! equal to first writing an RGBA color with a write swizzle and then reading
1618 //! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
1619 static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order)
1620 {
1621 	// make sure to update these tables when channel orders are updated
1622 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
1623 
1624 	static const TextureSwizzle INV		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1625 	static const TextureSwizzle R		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1626 	static const TextureSwizzle A		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
1627 	static const TextureSwizzle I		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0	}};
1628 	static const TextureSwizzle L		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ONE	}};
1629 	static const TextureSwizzle LA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3	}};
1630 	static const TextureSwizzle RG		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1631 	static const TextureSwizzle RA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
1632 	static const TextureSwizzle RGB		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_ONE	}};
1633 	static const TextureSwizzle RGBA	= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3	}};
1634 	static const TextureSwizzle D		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1635 	static const TextureSwizzle S		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1636 
1637 	const TextureSwizzle* swizzle;
1638 
1639 	switch (order)
1640 	{
1641 		case TextureFormat::R:			swizzle = &R;		break;
1642 		case TextureFormat::A:			swizzle = &A;		break;
1643 		case TextureFormat::I:			swizzle = &I;		break;
1644 		case TextureFormat::L:			swizzle = &L;		break;
1645 		case TextureFormat::LA:			swizzle = &LA;		break;
1646 		case TextureFormat::RG:			swizzle = &RG;		break;
1647 		case TextureFormat::RA:			swizzle = &RA;		break;
1648 		case TextureFormat::RGB:		swizzle = &RGB;		break;
1649 		case TextureFormat::RGBA:		swizzle = &RGBA;	break;
1650 		case TextureFormat::ARGB:		swizzle = &RGBA;	break;
1651 		case TextureFormat::ABGR:		swizzle = &RGBA;	break;
1652 		case TextureFormat::BGR:		swizzle = &RGB;		break;
1653 		case TextureFormat::BGRA:		swizzle = &RGBA;	break;
1654 		case TextureFormat::sR:			swizzle = &R;		break;
1655 		case TextureFormat::sRG:		swizzle = &RG;		break;
1656 		case TextureFormat::sRGB:		swizzle = &RGB;		break;
1657 		case TextureFormat::sRGBA:		swizzle = &RGBA;	break;
1658 		case TextureFormat::sBGR:		swizzle = &RGB;		break;
1659 		case TextureFormat::sBGRA:		swizzle = &RGBA;	break;
1660 		case TextureFormat::D:			swizzle = &D;		break;
1661 		case TextureFormat::S:			swizzle = &S;		break;
1662 
1663 		case TextureFormat::DS:
1664 			DE_ASSERT(false); // combined depth-stencil border color?
1665 			swizzle = &INV;
1666 			break;
1667 
1668 		default:
1669 			DE_ASSERT(false);
1670 			swizzle = &INV;
1671 			break;
1672 	}
1673 
1674 #ifdef DE_DEBUG
1675 
1676 	{
1677 		// check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
1678 		const TextureSwizzle& readSwizzle	= getChannelReadSwizzle(order);
1679 		const TextureSwizzle& writeSwizzle	= getChannelWriteSwizzle(order);
1680 
1681 		for (int ndx = 0; ndx < 4; ++ndx)
1682 		{
1683 			TextureSwizzle::Channel writeRead = readSwizzle.components[ndx];
1684 			if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE)
1685 				writeRead = writeSwizzle.components[(int)writeRead];
1686 			DE_ASSERT(writeRead == swizzle->components[ndx]);
1687 		}
1688 	}
1689 
1690 #endif
1691 
1692 	return *swizzle;
1693 }
1694 
1695 static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1696 {
1697 	return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0),
1698 					  (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0),
1699 					  (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0),
1700 					  (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0));
1701 }
1702 
1703 static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1704 {
1705 	return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0),
1706 					  (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0),
1707 					  (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0),
1708 					  (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0));
1709 }
1710 
1711 static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits)
1712 {
1713 	return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0),
1714 					  (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0),
1715 					  (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0),
1716 					  (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0));
1717 }
1718 
1719 static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler)
1720 {
1721 	const tcu::TextureChannelClass	channelClass	= getTextureChannelClass(format.type);
1722 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1723 	const bool						isFloat			= channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1724 	const bool						isSigned		= channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1725 	const float						valueMin		= (isSigned) ? (-1.0f) : (0.0f);
1726 	const float						valueMax		= 1.0f;
1727 	Vec4							result;
1728 
1729 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
1730 			  channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1731 			  channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
1732 
1733 	for (int c = 0; c < 4; c++)
1734 	{
1735 		const TextureSwizzle::Channel map = channelMap[c];
1736 		if (map == TextureSwizzle::CHANNEL_ZERO)
1737 			result[c] = 0.0f;
1738 		else if (map == TextureSwizzle::CHANNEL_ONE)
1739 			result[c] = 1.0f;
1740 		else if (isFloat)
1741 		{
1742 			// floating point values are not clamped
1743 			result[c] = sampler.borderColor.getAccess<float>()[(int)map];
1744 		}
1745 		else
1746 		{
1747 			// fixed point values are clamped to a representable range
1748 			result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax);
1749 		}
1750 	}
1751 
1752 	return result;
1753 }
1754 
1755 static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler)
1756 {
1757 	const tcu::TextureChannelClass	channelClass	= getTextureChannelClass(format.type);
1758 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1759 	const IVec4						channelBits		= getChannelBitDepth(format.type);
1760 	const IVec4						valueMin		= getNBitSignedIntegerVec4MinValue(channelBits);
1761 	const IVec4						valueMax		= getNBitSignedIntegerVec4MaxValue(channelBits);
1762 	IVec4							result;
1763 
1764 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
1765 	DE_UNREF(channelClass);
1766 
1767 	for (int c = 0; c < 4; c++)
1768 	{
1769 		const TextureSwizzle::Channel map = channelMap[c];
1770 		if (map == TextureSwizzle::CHANNEL_ZERO)
1771 			result[c] = 0;
1772 		else if (map == TextureSwizzle::CHANNEL_ONE)
1773 			result[c] = 1;
1774 		else
1775 		{
1776 			// integer values are clamped to a representable range
1777 			result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]);
1778 		}
1779 	}
1780 
1781 	return result;
1782 }
1783 
1784 static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler)
1785 {
1786 	const tcu::TextureChannelClass	channelClass	= getTextureChannelClass(format.type);
1787 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1788 	const IVec4						channelBits		= getChannelBitDepth(format.type);
1789 	const UVec4						valueMax		= getNBitUnsignedIntegerVec4MaxValue(channelBits);
1790 	UVec4							result;
1791 
1792 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
1793 	DE_UNREF(channelClass);
1794 
1795 	for (int c = 0; c < 4; c++)
1796 	{
1797 		const TextureSwizzle::Channel map = channelMap[c];
1798 		if (map == TextureSwizzle::CHANNEL_ZERO)
1799 			result[c] = 0;
1800 		else if (map == TextureSwizzle::CHANNEL_ONE)
1801 			result[c] = 1;
1802 		else
1803 		{
1804 			// integer values are clamped to a representable range
1805 			result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]);
1806 		}
1807 	}
1808 
1809 	return result;
1810 }
1811 
1812 template <typename ScalarType>
1813 tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler)
1814 {
1815 	const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1816 
1817 	switch (channelClass)
1818 	{
1819 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1820 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1821 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1822 			return getTextureBorderColorFloat(format, sampler).cast<ScalarType>();
1823 
1824 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1825 			return getTextureBorderColorInt(format, sampler).cast<ScalarType>();
1826 
1827 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1828 			return getTextureBorderColorUint(format, sampler).cast<ScalarType>();
1829 
1830 		default:
1831 			DE_ASSERT(false);
1832 			return tcu::Vector<ScalarType, 4>();
1833 	}
1834 }
1835 
1836 // instantiation
1837 template tcu::Vector<float, 4>		sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1838 template tcu::Vector<deInt32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1839 template tcu::Vector<deUint32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1840 
1841 } // tcu
1842