Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Tester Core
      3  * ----------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Texture utilities.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuTextureUtil.hpp"
     25 #include "tcuVectorUtil.hpp"
     26 #include "deRandom.hpp"
     27 #include "deMath.h"
     28 #include "deMemory.h"
     29 
     30 #include <limits>
     31 
     32 namespace tcu
     33 {
     34 
     35 static 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 
     43 static inline float linearChannelToSRGB (float cl)
     44 {
     45 	if (cl <= 0.0f)
     46 		return 0.0f;
     47 	else if (cl < 0.0031308f)
     48 		return 12.92f*cl;
     49 	else if (cl < 1.0f)
     50 		return 1.055f*deFloatPow(cl, 0.41666f) - 0.055f;
     51 	else
     52 		return 1.0f;
     53 }
     54 
     55 //! Convert sRGB to linear colorspace
     56 Vec4 sRGBToLinear (const Vec4& cs)
     57 {
     58 	return Vec4(sRGBChannelToLinear(cs[0]),
     59 				sRGBChannelToLinear(cs[1]),
     60 				sRGBChannelToLinear(cs[2]),
     61 				cs[3]);
     62 }
     63 
     64 //! Convert from linear to sRGB colorspace
     65 Vec4 linearToSRGB (const Vec4& cl)
     66 {
     67 	return Vec4(linearChannelToSRGB(cl[0]),
     68 				linearChannelToSRGB(cl[1]),
     69 				linearChannelToSRGB(cl[2]),
     70 				cl[3]);
     71 }
     72 
     73 //! Get texture channel class for format
     74 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
     75 {
     76 	switch (channelType)
     77 	{
     78 		case TextureFormat::SNORM_INT8:						return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
     79 		case TextureFormat::SNORM_INT16:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
     80 		case TextureFormat::UNORM_INT8:						return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     81 		case TextureFormat::UNORM_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     82 		case TextureFormat::UNORM_SHORT_565:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     83 		case TextureFormat::UNORM_SHORT_555:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     84 		case TextureFormat::UNORM_SHORT_4444:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     85 		case TextureFormat::UNORM_SHORT_5551:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     86 		case TextureFormat::UNORM_INT_101010:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     87 		case TextureFormat::UNORM_INT_1010102_REV:			return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
     88 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
     89 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return TEXTURECHANNELCLASS_FLOATING_POINT;
     90 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return TEXTURECHANNELCLASS_FLOATING_POINT;
     91 		case TextureFormat::SIGNED_INT8:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
     92 		case TextureFormat::SIGNED_INT16:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
     93 		case TextureFormat::SIGNED_INT32:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
     94 		case TextureFormat::UNSIGNED_INT8:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
     95 		case TextureFormat::UNSIGNED_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
     96 		case TextureFormat::UNSIGNED_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
     97 		case TextureFormat::HALF_FLOAT:						return TEXTURECHANNELCLASS_FLOATING_POINT;
     98 		case TextureFormat::FLOAT:							return TEXTURECHANNELCLASS_FLOATING_POINT;
     99 		default:											return TEXTURECHANNELCLASS_LAST;
    100 	}
    101 }
    102 
    103 /*--------------------------------------------------------------------*//*!
    104  * \brief Get access to subregion of pixel buffer
    105  * \param access	Parent access object
    106  * \param x			X offset
    107  * \param y			Y offset
    108  * \param z			Z offset
    109  * \param width		Width
    110  * \param height	Height
    111  * \param depth		Depth
    112  * \return Access object that targets given subregion of parent access object
    113  *//*--------------------------------------------------------------------*/
    114 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
    115 {
    116 	DE_ASSERT(de::inBounds(x, 0, access.getWidth())		&& de::inRange(x+width,		x, access.getWidth()));
    117 	DE_ASSERT(de::inBounds(y, 0, access.getHeight())	&& de::inRange(y+height,	y, access.getHeight()));
    118 	DE_ASSERT(de::inBounds(z, 0, access.getDepth())		&& de::inRange(z+depth,		z, access.getDepth()));
    119 	return ConstPixelBufferAccess(access.getFormat(), width, height, depth, access.getRowPitch(), access.getSlicePitch(),
    120 								  (const deUint8*)access.getDataPtr() + access.getFormat().getPixelSize()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
    121 }
    122 
    123 /*--------------------------------------------------------------------*//*!
    124  * \brief Get access to subregion of pixel buffer
    125  * \param access	Parent access object
    126  * \param x			X offset
    127  * \param y			Y offset
    128  * \param z			Z offset
    129  * \param width		Width
    130  * \param height	Height
    131  * \param depth		Depth
    132  * \return Access object that targets given subregion of parent access object
    133  *//*--------------------------------------------------------------------*/
    134 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
    135 {
    136 	DE_ASSERT(de::inBounds(x, 0, access.getWidth())		&& de::inRange(x+width,		x, access.getWidth()));
    137 	DE_ASSERT(de::inBounds(y, 0, access.getHeight())	&& de::inRange(y+height,	y, access.getHeight()));
    138 	DE_ASSERT(de::inBounds(z, 0, access.getDepth())		&& de::inRange(z+depth,		z, access.getDepth()));
    139 	return PixelBufferAccess(access.getFormat(), width, height, depth, access.getRowPitch(), access.getSlicePitch(),
    140 							 (deUint8*)access.getDataPtr() + access.getFormat().getPixelSize()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
    141 }
    142 
    143 /*--------------------------------------------------------------------*//*!
    144  * \brief Get access to subregion of pixel buffer
    145  * \param access	Parent access object
    146  * \param x			X offset
    147  * \param y			Y offset
    148  * \param width		Width
    149  * \param height	Height
    150  * \return Access object that targets given subregion of parent access object
    151  *//*--------------------------------------------------------------------*/
    152 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
    153 {
    154 	return getSubregion(access, x, y, 0, width, height, 1);
    155 }
    156 
    157 /*--------------------------------------------------------------------*//*!
    158  * \brief Get access to subregion of pixel buffer
    159  * \param access	Parent access object
    160  * \param x			X offset
    161  * \param y			Y offset
    162  * \param width		Width
    163  * \param height	Height
    164  * \return Access object that targets given subregion of parent access object
    165  *//*--------------------------------------------------------------------*/
    166 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
    167 {
    168 	return getSubregion(access, x, y, 0, width, height, 1);
    169 }
    170 
    171 /*--------------------------------------------------------------------*//*!
    172  * \brief Flip rows in Y direction
    173  * \param access Access object
    174  * \return Modified access object where Y coordinates are reversed
    175  *//*--------------------------------------------------------------------*/
    176 PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
    177 {
    178 	const int	rowPitch		= access.getRowPitch();
    179 	const int	offsetToLast	= rowPitch*(access.getHeight()-1);
    180 
    181 	return PixelBufferAccess(access.getFormat(), access.getWidth(), access.getHeight(), access.getDepth(),
    182 							 -rowPitch, access.getSlicePitch(), (deUint8*)access.getDataPtr() + offsetToLast);
    183 }
    184 
    185 /*--------------------------------------------------------------------*//*!
    186  * \brief Flip rows in Y direction
    187  * \param access Access object
    188  * \return Modified access object where Y coordinates are reversed
    189  *//*--------------------------------------------------------------------*/
    190 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
    191 {
    192 	const int	rowPitch		= access.getRowPitch();
    193 	const int	offsetToLast	= rowPitch*(access.getHeight()-1);
    194 
    195 	return ConstPixelBufferAccess(access.getFormat(), access.getWidth(), access.getHeight(), access.getDepth(),
    196 								  -rowPitch, access.getSlicePitch(), (const deUint8*)access.getDataPtr() + offsetToLast);
    197 }
    198 
    199 static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType)
    200 {
    201 	float cMin = 0.0f;
    202 	float cMax = 0.0f;
    203 
    204 	switch (channelType)
    205 	{
    206 		// Signed normalized formats.
    207 		case TextureFormat::SNORM_INT8:
    208 		case TextureFormat::SNORM_INT16:					cMin = -1.0f;			cMax = 1.0f;			break;
    209 
    210 		// Unsigned normalized formats.
    211 		case TextureFormat::UNORM_INT8:
    212 		case TextureFormat::UNORM_INT16:
    213 		case TextureFormat::UNORM_SHORT_565:
    214 		case TextureFormat::UNORM_SHORT_4444:
    215 		case TextureFormat::UNORM_INT_101010:
    216 		case TextureFormat::UNORM_INT_1010102_REV:			cMin = 0.0f;			cMax = 1.0f;			break;
    217 
    218 		// Misc formats.
    219 		case TextureFormat::SIGNED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
    220 		case TextureFormat::SIGNED_INT16:					cMin = -32768.0f;		cMax = 32767.0f;		break;
    221 		case TextureFormat::SIGNED_INT32:					cMin = -2147483648.0f;	cMax = 2147483647.0f;	break;
    222 		case TextureFormat::UNSIGNED_INT8:					cMin = 0.0f;			cMax = 255.0f;			break;
    223 		case TextureFormat::UNSIGNED_INT16:					cMin = 0.0f;			cMax = 65535.0f;		break;
    224 		case TextureFormat::UNSIGNED_INT32:					cMin = 0.0f;			cMax = 4294967295.f;	break;
    225 		case TextureFormat::HALF_FLOAT:						cMin = -1e3f;			cMax = 1e3f;			break;
    226 		case TextureFormat::FLOAT:							cMin = -1e5f;			cMax = 1e5f;			break;
    227 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	cMin = 0.0f;			cMax = 1e4f;			break;
    228 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		cMin = 0.0f;			cMax = 1e5f;			break;
    229 
    230 		default:
    231 			DE_ASSERT(false);
    232 	}
    233 
    234 	return Vec2(cMin, cMax);
    235 }
    236 
    237 /*--------------------------------------------------------------------*//*!
    238  * \brief Get standard parameters for testing texture format
    239  *
    240  * Returns TextureFormatInfo that describes good parameters for exercising
    241  * given TextureFormat. Parameters include value ranges per channel and
    242  * suitable lookup scaling and bias in order to reduce result back to
    243  * 0..1 range.
    244  *//*--------------------------------------------------------------------*/
    245 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
    246 {
    247 	// Special cases.
    248 	if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV))
    249 		return TextureFormatInfo(Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f),
    250 								 Vec4(	 1023.0f,		 1023.0f,		 1023.0f,		 3.0f),
    251 								 Vec4(1.0f/1023.f,	1.0f/1023.0f,	1.0f/1023.0f,	1.0f/3.0f),
    252 								 Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f));
    253 	else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
    254 		return TextureFormatInfo(Vec4(0.0f,	0.0f,	0.0f,	0.0f),
    255 								 Vec4(1.0f,	1.0f,	1.0f,	0.0f),
    256 								 Vec4(1.0f,	1.0f,	1.0f,	1.0f),
    257 								 Vec4(0.0f,	0.0f,	0.0f,	0.0f)); // Depth / stencil formats.
    258 	else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
    259 		return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
    260 								 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
    261 								 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
    262 								 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
    263 
    264 	Vec2	cRange		= getChannelValueRange(format.type);
    265 	BVec4	chnMask		= BVec4(false);
    266 
    267 	switch (format.order)
    268 	{
    269 		case TextureFormat::R:		chnMask = BVec4(true,	false,	false,	false);		break;
    270 		case TextureFormat::A:		chnMask = BVec4(false,	false,	false,	true);		break;
    271 		case TextureFormat::L:		chnMask = BVec4(true,	true,	true,	false);		break;
    272 		case TextureFormat::LA:		chnMask = BVec4(true,	true,	true,	true);		break;
    273 		case TextureFormat::RG:		chnMask = BVec4(true,	true,	false,	false);		break;
    274 		case TextureFormat::RGB:	chnMask = BVec4(true,	true,	true,	false);		break;
    275 		case TextureFormat::RGBA:	chnMask = BVec4(true,	true,	true,	true);		break;
    276 		case TextureFormat::sRGB:	chnMask = BVec4(true,	true,	true,	false);		break;
    277 		case TextureFormat::sRGBA:	chnMask = BVec4(true,	true,	true,	true);		break;
    278 		case TextureFormat::D:		chnMask = BVec4(true,	true,	true,	false);		break;
    279 		case TextureFormat::DS:		chnMask = BVec4(true,	true,	true,	true);		break;
    280 		default:
    281 			DE_ASSERT(false);
    282 	}
    283 
    284 	float	scale	= 1.0f / (cRange[1] - cRange[0]);
    285 	float	bias	= -cRange[0] * scale;
    286 
    287 	return TextureFormatInfo(select(cRange[0],	0.0f, chnMask),
    288 							 select(cRange[1],	0.0f, chnMask),
    289 							 select(scale,		1.0f, chnMask),
    290 							 select(bias,		0.0f, chnMask));
    291 }
    292 
    293 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
    294 {
    295 	switch (channelType)
    296 	{
    297 		case TextureFormat::SNORM_INT8:						return IVec4(8);
    298 		case TextureFormat::SNORM_INT16:					return IVec4(16);
    299 		case TextureFormat::SNORM_INT32:					return IVec4(32);
    300 		case TextureFormat::UNORM_INT8:						return IVec4(8);
    301 		case TextureFormat::UNORM_INT16:					return IVec4(16);
    302 		case TextureFormat::UNORM_INT32:					return IVec4(32);
    303 		case TextureFormat::UNORM_SHORT_565:				return IVec4(5,6,5,0);
    304 		case TextureFormat::UNORM_SHORT_4444:				return IVec4(4);
    305 		case TextureFormat::UNORM_SHORT_555:				return IVec4(5,5,5,0);
    306 		case TextureFormat::UNORM_SHORT_5551:				return IVec4(5,5,5,1);
    307 		case TextureFormat::UNORM_INT_101010:				return IVec4(10,10,10,0);
    308 		case TextureFormat::UNORM_INT_1010102_REV:			return IVec4(10,10,10,2);
    309 		case TextureFormat::SIGNED_INT8:					return IVec4(8);
    310 		case TextureFormat::SIGNED_INT16:					return IVec4(16);
    311 		case TextureFormat::SIGNED_INT32:					return IVec4(32);
    312 		case TextureFormat::UNSIGNED_INT8:					return IVec4(8);
    313 		case TextureFormat::UNSIGNED_INT16:					return IVec4(16);
    314 		case TextureFormat::UNSIGNED_INT32:					return IVec4(32);
    315 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return IVec4(10,10,10,2);
    316 		case TextureFormat::UNSIGNED_INT_24_8:				return IVec4(24,0,0,8);
    317 		case TextureFormat::HALF_FLOAT:						return IVec4(16);
    318 		case TextureFormat::FLOAT:							return IVec4(32);
    319 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(11,11,10,0);
    320 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return IVec4(9,9,9,0);
    321 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(32,0,0,8);
    322 		default:
    323 			DE_ASSERT(false);
    324 			return IVec4(0);
    325 	}
    326 }
    327 
    328 IVec4 getTextureFormatBitDepth (const TextureFormat& format)
    329 {
    330 	IVec4	chnBits		= getChannelBitDepth(format.type);
    331 	BVec4	chnMask		= BVec4(false);
    332 	IVec4	chnSwz		(0,1,2,3);
    333 
    334 	switch (format.order)
    335 	{
    336 		case TextureFormat::R:		chnMask = BVec4(true,	false,	false,	false);		break;
    337 		case TextureFormat::A:		chnMask = BVec4(false,	false,	false,	true);		break;
    338 		case TextureFormat::RA:		chnMask = BVec4(true,	false,	false,	true);		break;
    339 		case TextureFormat::L:		chnMask = BVec4(true,	true,	true,	false);		break;
    340 		case TextureFormat::I:		chnMask = BVec4(true,	true,	true,	true);		break;
    341 		case TextureFormat::LA:		chnMask = BVec4(true,	true,	true,	true);		break;
    342 		case TextureFormat::RG:		chnMask = BVec4(true,	true,	false,	false);		break;
    343 		case TextureFormat::RGB:	chnMask = BVec4(true,	true,	true,	false);		break;
    344 		case TextureFormat::RGBA:	chnMask = BVec4(true,	true,	true,	true);		break;
    345 		case TextureFormat::BGRA:	chnMask = BVec4(true,	true,	true,	true);		chnSwz = IVec4(2, 1, 0, 3);	break;
    346 		case TextureFormat::ARGB:	chnMask = BVec4(true,	true,	true,	true);		chnSwz = IVec4(1, 2, 3, 0);	break;
    347 		case TextureFormat::sRGB:	chnMask = BVec4(true,	true,	true,	false);		break;
    348 		case TextureFormat::sRGBA:	chnMask = BVec4(true,	true,	true,	true);		break;
    349 		case TextureFormat::D:		chnMask = BVec4(true,	false,	false,	false);		break;
    350 		case TextureFormat::DS:		chnMask = BVec4(true,	false,	false,	true);		break;
    351 		case TextureFormat::S:		chnMask = BVec4(false,	false,	false,	true);		break;
    352 		default:
    353 			DE_ASSERT(false);
    354 	}
    355 
    356 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
    357 }
    358 
    359 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
    360 {
    361 	switch (channelType)
    362 	{
    363 		case TextureFormat::SNORM_INT8:
    364 		case TextureFormat::SNORM_INT16:
    365 		case TextureFormat::SNORM_INT32:
    366 		case TextureFormat::UNORM_INT8:
    367 		case TextureFormat::UNORM_INT16:
    368 		case TextureFormat::UNORM_INT32:
    369 		case TextureFormat::UNORM_SHORT_565:
    370 		case TextureFormat::UNORM_SHORT_4444:
    371 		case TextureFormat::UNORM_SHORT_555:
    372 		case TextureFormat::UNORM_SHORT_5551:
    373 		case TextureFormat::UNORM_INT_101010:
    374 		case TextureFormat::UNORM_INT_1010102_REV:
    375 		case TextureFormat::SIGNED_INT8:
    376 		case TextureFormat::SIGNED_INT16:
    377 		case TextureFormat::SIGNED_INT32:
    378 		case TextureFormat::UNSIGNED_INT8:
    379 		case TextureFormat::UNSIGNED_INT16:
    380 		case TextureFormat::UNSIGNED_INT32:
    381 		case TextureFormat::UNSIGNED_INT_1010102_REV:
    382 		case TextureFormat::UNSIGNED_INT_24_8:
    383 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
    384 			return getChannelBitDepth(channelType);
    385 
    386 		case TextureFormat::HALF_FLOAT:						return IVec4(10);
    387 		case TextureFormat::FLOAT:							return IVec4(23);
    388 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(6,6,5,0);
    389 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(23,0,0,8);
    390 		default:
    391 			DE_ASSERT(false);
    392 			return IVec4(0);
    393 	}
    394 }
    395 
    396 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
    397 {
    398 	IVec4	chnBits		= getChannelMantissaBitDepth(format.type);
    399 	BVec4	chnMask		= BVec4(false);
    400 	IVec4	chnSwz		(0,1,2,3);
    401 
    402 	switch (format.order)
    403 	{
    404 		case TextureFormat::R:		chnMask = BVec4(true,	false,	false,	false);		break;
    405 		case TextureFormat::A:		chnMask = BVec4(false,	false,	false,	true);		break;
    406 		case TextureFormat::RA:		chnMask = BVec4(true,	false,	false,	true);		break;
    407 		case TextureFormat::L:		chnMask = BVec4(true,	true,	true,	false);		break;
    408 		case TextureFormat::I:		chnMask = BVec4(true,	true,	true,	true);		break;
    409 		case TextureFormat::LA:		chnMask = BVec4(true,	true,	true,	true);		break;
    410 		case TextureFormat::RG:		chnMask = BVec4(true,	true,	false,	false);		break;
    411 		case TextureFormat::RGB:	chnMask = BVec4(true,	true,	true,	false);		break;
    412 		case TextureFormat::RGBA:	chnMask = BVec4(true,	true,	true,	true);		break;
    413 		case TextureFormat::BGRA:	chnMask = BVec4(true,	true,	true,	true);		chnSwz = IVec4(2, 1, 0, 3);	break;
    414 		case TextureFormat::ARGB:	chnMask = BVec4(true,	true,	true,	true);		chnSwz = IVec4(1, 2, 3, 0);	break;
    415 		case TextureFormat::sRGB:	chnMask = BVec4(true,	true,	true,	false);		break;
    416 		case TextureFormat::sRGBA:	chnMask = BVec4(true,	true,	true,	true);		break;
    417 		case TextureFormat::D:		chnMask = BVec4(true,	false,	false,	false);		break;
    418 		case TextureFormat::DS:		chnMask = BVec4(true,	false,	false,	true);		break;
    419 		case TextureFormat::S:		chnMask = BVec4(false,	false,	false,	true);		break;
    420 		default:
    421 			DE_ASSERT(false);
    422 	}
    423 
    424 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
    425 }
    426 
    427 static inline float linearInterpolate (float t, float minVal, float maxVal)
    428 {
    429 	return minVal + (maxVal - minVal) * t;
    430 }
    431 
    432 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
    433 {
    434 	return a + (b - a) * t;
    435 }
    436 
    437 enum
    438 {
    439 	CLEAR_OPTIMIZE_THRESHOLD		= 128,
    440 	CLEAR_OPTIMIZE_MAX_PIXEL_SIZE	= 8
    441 };
    442 
    443 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
    444 {
    445 	deUint8*	dstPtr	= (deUint8*)dst.getDataPtr() + z*dst.getSlicePitch() + y*dst.getRowPitch();
    446 	int			width	= dst.getWidth();
    447 
    448 	if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize) && deIsAlignedPtr(dstPtr, pixelSize))
    449 	{
    450 		deUint64 val;
    451 		memcpy(&val, pixel, sizeof(val));
    452 
    453 		for (int i = 0; i < width; i++)
    454 			((deUint64*)dstPtr)[i] = val;
    455 	}
    456 	else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize) && deIsAlignedPtr(dstPtr, pixelSize))
    457 	{
    458 		deUint32 val;
    459 		memcpy(&val, pixel, sizeof(val));
    460 
    461 		for (int i = 0; i < width; i++)
    462 			((deUint32*)dstPtr)[i] = val;
    463 	}
    464 	else
    465 	{
    466 		for (int i = 0; i < width; i++)
    467 			for (int j = 0; j < pixelSize; j++)
    468 				dstPtr[i*pixelSize+j] = pixel[j];
    469 	}
    470 }
    471 
    472 void clear (const PixelBufferAccess& access, const Vec4& color)
    473 {
    474 	int pixelSize = access.getFormat().getPixelSize();
    475 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
    476 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
    477 	{
    478 		// Convert to destination format.
    479 		union
    480 		{
    481 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
    482 			deUint64	u64; // Forces 64-bit alignment.
    483 		} pixel;
    484 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
    485 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
    486 
    487 		for (int z = 0; z < access.getDepth(); z++)
    488 			for (int y = 0; y < access.getHeight(); y++)
    489 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
    490 	}
    491 	else
    492 	{
    493 		for (int z = 0; z < access.getDepth(); z++)
    494 			for (int y = 0; y < access.getHeight(); y++)
    495 				for (int x = 0; x < access.getWidth(); x++)
    496 					access.setPixel(color, x, y, z);
    497 	}
    498 }
    499 
    500 void clear (const PixelBufferAccess& access, const IVec4& color)
    501 {
    502 	int pixelSize = access.getFormat().getPixelSize();
    503 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
    504 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
    505 	{
    506 		// Convert to destination format.
    507 		union
    508 		{
    509 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
    510 			deUint64	u64; // Forces 64-bit alignment.
    511 		} pixel;
    512 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
    513 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
    514 
    515 		for (int z = 0; z < access.getDepth(); z++)
    516 			for (int y = 0; y < access.getHeight(); y++)
    517 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
    518 	}
    519 	else
    520 	{
    521 		for (int z = 0; z < access.getDepth(); z++)
    522 			for (int y = 0; y < access.getHeight(); y++)
    523 				for (int x = 0; x < access.getWidth(); x++)
    524 					access.setPixel(color, x, y, z);
    525 	}
    526 }
    527 
    528 void clearDepth (const PixelBufferAccess& access, float depth)
    529 {
    530 	int pixelSize = access.getFormat().getPixelSize();
    531 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
    532 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
    533 	{
    534 		// Convert to destination format.
    535 		union
    536 		{
    537 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
    538 			deUint64	u64; // Forces 64-bit alignment.
    539 		} pixel;
    540 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
    541 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixDepth(depth, 0, 0);
    542 
    543 		for (int z = 0; z < access.getDepth(); z++)
    544 			for (int y = 0; y < access.getHeight(); y++)
    545 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
    546 	}
    547 	else
    548 	{
    549 		for (int z = 0; z < access.getDepth(); z++)
    550 			for (int y = 0; y < access.getHeight(); y++)
    551 				for (int x = 0; x < access.getWidth(); x++)
    552 					access.setPixDepth(depth, x, y, z);
    553 	}
    554 }
    555 
    556 void clearStencil (const PixelBufferAccess& access, int stencil)
    557 {
    558 	int pixelSize = access.getFormat().getPixelSize();
    559 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
    560 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
    561 	{
    562 		// Convert to destination format.
    563 		union
    564 		{
    565 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
    566 			deUint64	u64; // Forces 64-bit alignment.
    567 		} pixel;
    568 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
    569 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixStencil(stencil, 0, 0);
    570 
    571 		for (int z = 0; z < access.getDepth(); z++)
    572 			for (int y = 0; y < access.getHeight(); y++)
    573 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
    574 	}
    575 	else
    576 	{
    577 		for (int z = 0; z < access.getDepth(); z++)
    578 			for (int y = 0; y < access.getHeight(); y++)
    579 				for (int x = 0; x < access.getWidth(); x++)
    580 					access.setPixStencil(stencil, x, y, z);
    581 	}
    582 }
    583 
    584 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
    585 {
    586 	DE_ASSERT(access.getHeight() == 1);
    587 	for (int x = 0; x < access.getWidth(); x++)
    588 	{
    589 		float s	= ((float)x + 0.5f) / (float)access.getWidth();
    590 
    591 		float r	= linearInterpolate(s, minVal.x(), maxVal.x());
    592 		float g = linearInterpolate(s, minVal.y(), maxVal.y());
    593 		float b = linearInterpolate(s, minVal.z(), maxVal.z());
    594 		float a = linearInterpolate(s, minVal.w(), maxVal.w());
    595 
    596 		access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
    597 	}
    598 }
    599 
    600 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
    601 {
    602 	for (int y = 0; y < access.getHeight(); y++)
    603 	{
    604 		for (int x = 0; x < access.getWidth(); x++)
    605 		{
    606 			float s	= ((float)x + 0.5f) / (float)access.getWidth();
    607 			float t	= ((float)y + 0.5f) / (float)access.getHeight();
    608 
    609 			float r	= linearInterpolate((      s  +       t) *0.5f, minVal.x(), maxVal.x());
    610 			float g = linearInterpolate((      s  + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
    611 			float b = linearInterpolate(((1.0f-s) +       t) *0.5f, minVal.z(), maxVal.z());
    612 			float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
    613 
    614 			access.setPixel(tcu::Vec4(r, g, b, a), x, y);
    615 		}
    616 	}
    617 }
    618 
    619 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal)
    620 {
    621 	for (int z = 0; z < dst.getDepth(); z++)
    622 	{
    623 		for (int y = 0; y < dst.getHeight(); y++)
    624 		{
    625 			for (int x = 0; x < dst.getWidth(); x++)
    626 			{
    627 				float s = ((float)x + 0.5f) / (float)dst.getWidth();
    628 				float t = ((float)y + 0.5f) / (float)dst.getHeight();
    629 				float p = ((float)z + 0.5f) / (float)dst.getDepth();
    630 
    631 				float r = linearInterpolate(s,						minVal.x(), maxVal.x());
    632 				float g = linearInterpolate(t,						minVal.y(), maxVal.y());
    633 				float b = linearInterpolate(p,						minVal.z(), maxVal.z());
    634 				float a = linearInterpolate(1.0f - (s+t+p)/3.0f,	minVal.w(), maxVal.w());
    635 
    636 				dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
    637 			}
    638 		}
    639 	}
    640 }
    641 
    642 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
    643 {
    644 	if (access.getHeight() == 1 && access.getDepth() == 1)
    645 		fillWithComponentGradients1D(access, minVal, maxVal);
    646 	else if (access.getDepth() == 1)
    647 		fillWithComponentGradients2D(access, minVal, maxVal);
    648 	else
    649 		fillWithComponentGradients3D(access, minVal, maxVal);
    650 }
    651 
    652 void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    653 {
    654 	for (int x = 0; x < access.getWidth(); x++)
    655 	{
    656 		int mx = (x / cellSize) % 2;
    657 
    658 		if (mx)
    659 			access.setPixel(colorB, x, 0);
    660 		else
    661 			access.setPixel(colorA, x, 0);
    662 	}
    663 }
    664 
    665 void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    666 {
    667 	for (int y = 0; y < access.getHeight(); y++)
    668 	{
    669 		for (int x = 0; x < access.getWidth(); x++)
    670 		{
    671 			int mx = (x / cellSize) % 2;
    672 			int my = (y / cellSize) % 2;
    673 
    674 			if (mx ^ my)
    675 				access.setPixel(colorB, x, y);
    676 			else
    677 				access.setPixel(colorA, x, y);
    678 		}
    679 	}
    680 }
    681 
    682 void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    683 {
    684 	for (int z = 0; z < access.getDepth(); z++)
    685 	{
    686 		for (int y = 0; y < access.getHeight(); y++)
    687 		{
    688 			for (int x = 0; x < access.getWidth(); x++)
    689 			{
    690 				int mx = (x / cellSize) % 2;
    691 				int my = (y / cellSize) % 2;
    692 				int mz = (z / cellSize) % 2;
    693 
    694 				if (mx ^ my ^ mz)
    695 					access.setPixel(colorB, x, y, z);
    696 				else
    697 					access.setPixel(colorA, x, y, z);
    698 			}
    699 		}
    700 	}
    701 }
    702 
    703 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
    704 {
    705 	if (access.getHeight() == 1 && access.getDepth() == 1)
    706 		fillWithGrid1D(access, cellSize, colorA, colorB);
    707 	else if (access.getDepth() == 1)
    708 		fillWithGrid2D(access, cellSize, colorA, colorB);
    709 	else
    710 		fillWithGrid3D(access, cellSize, colorA, colorB);
    711 }
    712 
    713 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
    714 {
    715 	for (int y = 0; y < access.getHeight(); y++)
    716 	{
    717 		for (int x = 0; x < access.getWidth(); x++)
    718 		{
    719 			float s = ((float)x + 0.5f) / (float)access.getWidth();
    720 			float t = ((float)y + 0.5f) / (float)access.getHeight();
    721 
    722 			float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
    723 			float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
    724 
    725 			float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
    726 			access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
    727 		}
    728 	}
    729 }
    730 
    731 void fillWithRGBAQuads (const PixelBufferAccess& dst)
    732 {
    733 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
    734 	int width	= dst.getWidth();
    735 	int height	= dst.getHeight();
    736 	int	left	= width/2;
    737 	int top		= height/2;
    738 
    739 	clear(getSubregion(dst, 0,		0,		0, left,		top,		1),	Vec4(1.0f, 0.0f, 0.0f, 1.0f));
    740 	clear(getSubregion(dst, left,	0,		0, width-left,	top,		1),	Vec4(0.0f, 1.0f, 0.0f, 1.0f));
    741 	clear(getSubregion(dst, 0,		top,	0, left,		height-top,	1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
    742 	clear(getSubregion(dst, left,	top,	0, width-left,	height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
    743 }
    744 
    745 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
    746 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
    747 {
    748 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
    749 	std::vector<Vec2>	points(numBalls);
    750 	de::Random			rnd(seed);
    751 
    752 	for (int i = 0; i < numBalls; i++)
    753 	{
    754 		float x = rnd.getFloat();
    755 		float y = rnd.getFloat();
    756 		points[i] = (Vec2(x, y));
    757 	}
    758 
    759 	for (int y = 0; y < dst.getHeight(); y++)
    760 	for (int x = 0; x < dst.getWidth(); x++)
    761 	{
    762 		Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
    763 
    764 		float sum = 0.0f;
    765 		for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
    766 		{
    767 			Vec2	d = p - *i;
    768 			float	f = 0.01f / (d.x()*d.x() + d.y()*d.y());
    769 
    770 			sum += f;
    771 		}
    772 
    773 		dst.setPixel(Vec4(sum), x, y);
    774 	}
    775 }
    776 
    777 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src)
    778 {
    779 	int		width		= dst.getWidth();
    780 	int		height		= dst.getHeight();
    781 	int		depth		= dst.getDepth();
    782 
    783 	DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
    784 
    785 	if (src.getFormat() == dst.getFormat())
    786 	{
    787 		// Fast-path for matching formats.
    788 		int pixelSize = src.getFormat().getPixelSize();
    789 
    790 		for (int z = 0; z < depth; z++)
    791 		for (int y = 0; y < height; y++)
    792 			deMemcpy((deUint8*)dst.getDataPtr()			+ z*dst.getSlicePitch() + y*dst.getRowPitch(),
    793 					 (const deUint8*)src.getDataPtr()	+ z*src.getSlicePitch() + y*src.getRowPitch(),
    794 					 pixelSize*width);
    795 	}
    796 	else
    797 	{
    798 		TextureChannelClass		srcClass	= getTextureChannelClass(src.getFormat().type);
    799 		TextureChannelClass		dstClass	= getTextureChannelClass(dst.getFormat().type);
    800 		bool					srcIsInt	= srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    801 		bool					dstIsInt	= dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
    802 
    803 		if (srcIsInt && dstIsInt)
    804 		{
    805 			for (int z = 0; z < depth; z++)
    806 			for (int y = 0; y < height; y++)
    807 			for (int x = 0; x < width; x++)
    808 				dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
    809 		}
    810 		else
    811 		{
    812 			for (int z = 0; z < depth; z++)
    813 			for (int y = 0; y < height; y++)
    814 			for (int x = 0; x < width; x++)
    815 				dst.setPixel(src.getPixel(x, y, z), x, y, z);
    816 		}
    817 	}
    818 }
    819 
    820 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
    821 {
    822 	DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
    823 
    824 	Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
    825 					filter, filter, 0.0f, false);
    826 
    827 	float sX = (float)src.getWidth() / (float)dst.getWidth();
    828 	float sY = (float)src.getHeight() / (float)dst.getHeight();
    829 	float sZ = (float)src.getDepth() / (float)dst.getDepth();
    830 
    831 	if (dst.getDepth() == 1 && src.getDepth() == 1)
    832 	{
    833 		for (int y = 0; y < dst.getHeight(); y++)
    834 		for (int x = 0; x < dst.getWidth(); x++)
    835 			dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y);
    836 	}
    837 	else
    838 	{
    839 		for (int z = 0; z < dst.getDepth(); z++)
    840 		for (int y = 0; y < dst.getHeight(); y++)
    841 		for (int x = 0; x < dst.getWidth(); x++)
    842 			dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z);
    843 	}
    844 }
    845 
    846 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
    847 {
    848 	const TextureFormat& format = access.getFormat();
    849 
    850 	switch (format.type)
    851 	{
    852 		case TextureFormat::UNORM_INT8:
    853 		case TextureFormat::UNORM_INT16:
    854 			// Normalized unsigned formats.
    855 			minVal = Vec4(0.0f);
    856 			maxVal = Vec4(1.0f);
    857 			break;
    858 
    859 		case TextureFormat::SNORM_INT8:
    860 		case TextureFormat::SNORM_INT16:
    861 			// Normalized signed formats.
    862 			minVal = Vec4(-1.0f);
    863 			maxVal = Vec4(+1.0f);
    864 			break;
    865 
    866 		default:
    867 			// \note Samples every 4/8th pixel.
    868 			minVal = Vec4(std::numeric_limits<float>::max());
    869 			maxVal = Vec4(std::numeric_limits<float>::min());
    870 
    871 			for (int z = 0; z < access.getDepth(); z += 2)
    872 			{
    873 				for (int y = 0; y < access.getHeight(); y += 2)
    874 				{
    875 					for (int x = 0; x < access.getWidth(); x += 2)
    876 					{
    877 						Vec4 p = access.getPixel(x, y, z);
    878 
    879 						minVal[0] = de::min(minVal[0], p[0]);
    880 						minVal[1] = de::min(minVal[1], p[1]);
    881 						minVal[2] = de::min(minVal[2], p[2]);
    882 						minVal[3] = de::min(minVal[3], p[3]);
    883 
    884 						maxVal[0] = de::max(maxVal[0], p[0]);
    885 						maxVal[1] = de::max(maxVal[1], p[1]);
    886 						maxVal[2] = de::max(maxVal[2], p[2]);
    887 						maxVal[3] = de::max(maxVal[3], p[3]);
    888 					}
    889 				}
    890 			}
    891 			break;
    892 	}
    893 }
    894 
    895 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
    896 {
    897 	Vec4 minVal, maxVal;
    898 	estimatePixelValueRange(access, minVal, maxVal);
    899 
    900 	const float eps = 0.0001f;
    901 
    902 	for (int c = 0; c < 4; c++)
    903 	{
    904 		if (maxVal[c] - minVal[c] < eps)
    905 		{
    906 			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
    907 			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
    908 		}
    909 		else
    910 		{
    911 			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
    912 			bias[c]		= 0.0f - minVal[c]*scale[c];
    913 		}
    914 	}
    915 }
    916 
    917 int getCubeArrayFaceIndex (CubeFace face)
    918 {
    919 	DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
    920 
    921 	switch (face)
    922 	{
    923 		case CUBEFACE_POSITIVE_X:	return 0;
    924 		case CUBEFACE_NEGATIVE_X:	return 1;
    925 		case CUBEFACE_POSITIVE_Y:	return 2;
    926 		case CUBEFACE_NEGATIVE_Y:	return 3;
    927 		case CUBEFACE_POSITIVE_Z:	return 4;
    928 		case CUBEFACE_NEGATIVE_Z:	return 5;
    929 
    930 		default:
    931 			return -1;
    932 	}
    933 }
    934 
    935 } // tcu
    936