• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Texture utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuTextureUtil.hpp"
25 #include "tcuVectorUtil.hpp"
26 #include "deRandom.hpp"
27 #include "deMath.h"
28 #include "deMemory.h"
29 
30 #include <limits>
31 
32 namespace tcu
33 {
34 
sRGBChannelToLinear(float cs)35 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 
linearChannelToSRGB(float cl)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
sRGBToLinear(const Vec4 & cs)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
linearToSRGB(const Vec4 & cl)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
getTextureChannelClass(TextureFormat::ChannelType channelType)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  *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)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  *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)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  *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int width,int height)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  *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int width,int height)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  *//*--------------------------------------------------------------------*/
flipYAccess(const PixelBufferAccess & access)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  *//*--------------------------------------------------------------------*/
flipYAccess(const ConstPixelBufferAccess & access)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 
getChannelValueRange(TextureFormat::ChannelType channelType)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  *//*--------------------------------------------------------------------*/
getTextureFormatInfo(const TextureFormat & format)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 
getChannelBitDepth(TextureFormat::ChannelType channelType)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 
getTextureFormatBitDepth(const TextureFormat & format)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 
getChannelMantissaBitDepth(TextureFormat::ChannelType channelType)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 
getTextureFormatMantissaBitDepth(const TextureFormat & format)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 
linearInterpolate(float t,float minVal,float maxVal)427 static inline float linearInterpolate (float t, float minVal, float maxVal)
428 {
429 	return minVal + (maxVal - minVal) * t;
430 }
431 
linearInterpolate(float t,const Vec4 & a,const Vec4 & b)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 
fillRow(const PixelBufferAccess & dst,int y,int z,int pixelSize,const deUint8 * pixel)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 
clear(const PixelBufferAccess & access,const Vec4 & color)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 
clear(const PixelBufferAccess & access,const IVec4 & color)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 
clearDepth(const PixelBufferAccess & access,float depth)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 
clearStencil(const PixelBufferAccess & access,int stencil)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 
fillWithComponentGradients1D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)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 
fillWithComponentGradients2D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)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 
fillWithComponentGradients3D(const PixelBufferAccess & dst,const Vec4 & minVal,const Vec4 & maxVal)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 
fillWithComponentGradients(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)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 
fillWithGrid1D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)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 
fillWithGrid2D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)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 
fillWithGrid3D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)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 
fillWithGrid(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)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 
fillWithRepeatableGradient(const PixelBufferAccess & access,const Vec4 & colorA,const Vec4 & colorB)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 
fillWithRGBAQuads(const PixelBufferAccess & dst)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.
fillWithMetaballs(const PixelBufferAccess & dst,int numBalls,deUint32 seed)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 
copy(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src)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 
scale(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,Sampler::FilterMode filter)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 
estimatePixelValueRange(const ConstPixelBufferAccess & access,Vec4 & minVal,Vec4 & maxVal)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 
computePixelScaleBias(const ConstPixelBufferAccess & access,Vec4 & scale,Vec4 & bias)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 
getCubeArrayFaceIndex(CubeFace face)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