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