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