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