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