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 
isSRGB(TextureFormat format)73 bool isSRGB (TextureFormat format)
74 {
75 	return	format.order == TextureFormat::sR	||
76 			format.order == TextureFormat::sRG	||
77 			format.order == TextureFormat::sRGB	||
78 			format.order == TextureFormat::sRGBA;
79 }
80 
isCombinedDepthStencilType(TextureFormat::ChannelType type)81 bool isCombinedDepthStencilType (TextureFormat::ChannelType type)
82 {
83 	// make sure to update this if type table is updated
84 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
85 
86 	return	type == TextureFormat::UNSIGNED_INT_24_8 ||
87 			type == TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV;
88 }
89 
90 //! Get texture channel class for format
getTextureChannelClass(TextureFormat::ChannelType channelType)91 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
92 {
93 	// make sure this table is updated if format table is updated
94 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
95 
96 	switch (channelType)
97 	{
98 		case TextureFormat::SNORM_INT8:						return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
99 		case TextureFormat::SNORM_INT16:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
100 		case TextureFormat::SNORM_INT32:					return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
101 		case TextureFormat::UNORM_INT8:						return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
102 		case TextureFormat::UNORM_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
103 		case TextureFormat::UNORM_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
104 		case TextureFormat::UNORM_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
105 		case TextureFormat::UNORM_SHORT_565:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
106 		case TextureFormat::UNORM_SHORT_555:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
107 		case TextureFormat::UNORM_SHORT_4444:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
108 		case TextureFormat::UNORM_SHORT_5551:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
109 		case TextureFormat::UNORM_INT_101010:				return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
110 		case TextureFormat::UNORM_INT_1010102_REV:			return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
111 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
112 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return TEXTURECHANNELCLASS_FLOATING_POINT;
113 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return TEXTURECHANNELCLASS_FLOATING_POINT;
114 		case TextureFormat::UNSIGNED_INT_24_8:				return TEXTURECHANNELCLASS_LAST;					//!< packed unorm24-uint8
115 		case TextureFormat::SIGNED_INT8:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
116 		case TextureFormat::SIGNED_INT16:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
117 		case TextureFormat::SIGNED_INT32:					return TEXTURECHANNELCLASS_SIGNED_INTEGER;
118 		case TextureFormat::UNSIGNED_INT8:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
119 		case TextureFormat::UNSIGNED_INT16:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
120 		case TextureFormat::UNSIGNED_INT24:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
121 		case TextureFormat::UNSIGNED_INT32:					return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
122 		case TextureFormat::HALF_FLOAT:						return TEXTURECHANNELCLASS_FLOATING_POINT;
123 		case TextureFormat::FLOAT:							return TEXTURECHANNELCLASS_FLOATING_POINT;
124 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return TEXTURECHANNELCLASS_LAST;					//!< packed float32-pad24-uint8
125 		default:											return TEXTURECHANNELCLASS_LAST;
126 	}
127 }
128 
129 /*--------------------------------------------------------------------*//*!
130  * \brief Get access to subregion of pixel buffer
131  * \param access	Parent access object
132  * \param x			X offset
133  * \param y			Y offset
134  * \param z			Z offset
135  * \param width		Width
136  * \param height	Height
137  * \param depth		Depth
138  * \return Access object that targets given subregion of parent access object
139  *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)140 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
141 {
142 	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
143 	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
144 
145 	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
146 	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
147 
148 	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
149 	DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
150 
151 	return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
152 								  (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
153 }
154 
155 /*--------------------------------------------------------------------*//*!
156  * \brief Get access to subregion of pixel buffer
157  * \param access	Parent access object
158  * \param x			X offset
159  * \param y			Y offset
160  * \param z			Z offset
161  * \param width		Width
162  * \param height	Height
163  * \param depth		Depth
164  * \return Access object that targets given subregion of parent access object
165  *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)166 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
167 {
168 	DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
169 	DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
170 
171 	DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
172 	DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
173 
174 	DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
175 	DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
176 
177 	return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
178 							 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
179 }
180 
181 /*--------------------------------------------------------------------*//*!
182  * \brief Get access to subregion of pixel buffer
183  * \param access	Parent access object
184  * \param x			X offset
185  * \param y			Y offset
186  * \param width		Width
187  * \param height	Height
188  * \return Access object that targets given subregion of parent access object
189  *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int width,int height)190 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
191 {
192 	return getSubregion(access, x, y, 0, width, height, 1);
193 }
194 
195 /*--------------------------------------------------------------------*//*!
196  * \brief Get access to subregion of pixel buffer
197  * \param access	Parent access object
198  * \param x			X offset
199  * \param y			Y offset
200  * \param width		Width
201  * \param height	Height
202  * \return Access object that targets given subregion of parent access object
203  *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int width,int height)204 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
205 {
206 	return getSubregion(access, x, y, 0, width, height, 1);
207 }
208 
209 /*--------------------------------------------------------------------*//*!
210  * \brief Flip rows in Y direction
211  * \param access Access object
212  * \return Modified access object where Y coordinates are reversed
213  *//*--------------------------------------------------------------------*/
flipYAccess(const PixelBufferAccess & access)214 PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
215 {
216 	const int			rowPitch		= access.getRowPitch();
217 	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
218 	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
219 
220 	return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
221 }
222 
223 /*--------------------------------------------------------------------*//*!
224  * \brief Flip rows in Y direction
225  * \param access Access object
226  * \return Modified access object where Y coordinates are reversed
227  *//*--------------------------------------------------------------------*/
flipYAccess(const ConstPixelBufferAccess & access)228 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
229 {
230 	const int			rowPitch		= access.getRowPitch();
231 	const int			offsetToLast	= rowPitch*(access.getHeight()-1);
232 	const tcu::IVec3	pitch			(access.getPixelPitch(), -rowPitch, access.getSlicePitch());
233 
234 	return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
235 }
236 
getChannelValueRange(TextureFormat::ChannelType channelType)237 static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType)
238 {
239 	// make sure this table is updated if format table is updated
240 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
241 
242 	float cMin = 0.0f;
243 	float cMax = 0.0f;
244 
245 	switch (channelType)
246 	{
247 		// Signed normalized formats.
248 		case TextureFormat::SNORM_INT8:
249 		case TextureFormat::SNORM_INT16:
250 		case TextureFormat::SNORM_INT32:					cMin = -1.0f;			cMax = 1.0f;			break;
251 
252 		// Unsigned normalized formats.
253 		case TextureFormat::UNORM_INT8:
254 		case TextureFormat::UNORM_INT16:
255 		case TextureFormat::UNORM_INT24:
256 		case TextureFormat::UNORM_INT32:
257 		case TextureFormat::UNORM_SHORT_565:
258 		case TextureFormat::UNORM_SHORT_4444:
259 		case TextureFormat::UNORM_INT_101010:
260 		case TextureFormat::UNORM_INT_1010102_REV:			cMin = 0.0f;			cMax = 1.0f;			break;
261 
262 		// Misc formats.
263 		case TextureFormat::SIGNED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
264 		case TextureFormat::SIGNED_INT16:					cMin = -32768.0f;		cMax = 32767.0f;		break;
265 		case TextureFormat::SIGNED_INT32:					cMin = -2147483648.0f;	cMax = 2147483647.0f;	break;
266 		case TextureFormat::UNSIGNED_INT8:					cMin = 0.0f;			cMax = 255.0f;			break;
267 		case TextureFormat::UNSIGNED_INT16:					cMin = 0.0f;			cMax = 65535.0f;		break;
268 		case TextureFormat::UNSIGNED_INT24:					cMin = 0.0f;			cMax = 16777215.0f;		break;
269 		case TextureFormat::UNSIGNED_INT32:					cMin = 0.0f;			cMax = 4294967295.f;	break;
270 		case TextureFormat::HALF_FLOAT:						cMin = -1e3f;			cMax = 1e3f;			break;
271 		case TextureFormat::FLOAT:							cMin = -1e5f;			cMax = 1e5f;			break;
272 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	cMin = 0.0f;			cMax = 1e4f;			break;
273 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		cMin = 0.0f;			cMax = 1e5f;			break;
274 
275 		default:
276 			DE_ASSERT(false);
277 	}
278 
279 	return Vec2(cMin, cMax);
280 }
281 
282 /*--------------------------------------------------------------------*//*!
283  * \brief Get standard parameters for testing texture format
284  *
285  * Returns TextureFormatInfo that describes good parameters for exercising
286  * given TextureFormat. Parameters include value ranges per channel and
287  * suitable lookup scaling and bias in order to reduce result back to
288  * 0..1 range.
289  *//*--------------------------------------------------------------------*/
getTextureFormatInfo(const TextureFormat & format)290 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
291 {
292 	// Special cases.
293 	if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV))
294 		return TextureFormatInfo(Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f),
295 								 Vec4(	 1023.0f,		 1023.0f,		 1023.0f,		 3.0f),
296 								 Vec4(1.0f/1023.f,	1.0f/1023.0f,	1.0f/1023.0f,	1.0f/3.0f),
297 								 Vec4(	    0.0f,		    0.0f,		    0.0f,		 0.0f));
298 	else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
299 		return TextureFormatInfo(Vec4(0.0f,	0.0f,	0.0f,	0.0f),
300 								 Vec4(1.0f,	1.0f,	1.0f,	0.0f),
301 								 Vec4(1.0f,	1.0f,	1.0f,	1.0f),
302 								 Vec4(0.0f,	0.0f,	0.0f,	0.0f)); // Depth / stencil formats.
303 	else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
304 		return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
305 								 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
306 								 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
307 								 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
308 
309 	const Vec2						cRange		= getChannelValueRange(format.type);
310 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
311 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
312 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
313 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
314 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
315 	const float						scale		= 1.0f / (cRange[1] - cRange[0]);
316 	const float						bias		= -cRange[0] * scale;
317 
318 	return TextureFormatInfo(select(cRange[0],	0.0f, chnMask),
319 							 select(cRange[1],	0.0f, chnMask),
320 							 select(scale,		1.0f, chnMask),
321 							 select(bias,		0.0f, chnMask));
322 }
323 
getChannelBitDepth(TextureFormat::ChannelType channelType)324 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
325 {
326 	// make sure this table is updated if format table is updated
327 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
328 
329 	switch (channelType)
330 	{
331 		case TextureFormat::SNORM_INT8:						return IVec4(8);
332 		case TextureFormat::SNORM_INT16:					return IVec4(16);
333 		case TextureFormat::SNORM_INT32:					return IVec4(32);
334 		case TextureFormat::UNORM_INT8:						return IVec4(8);
335 		case TextureFormat::UNORM_INT16:					return IVec4(16);
336 		case TextureFormat::UNORM_INT24:					return IVec4(24);
337 		case TextureFormat::UNORM_INT32:					return IVec4(32);
338 		case TextureFormat::UNORM_SHORT_565:				return IVec4(5,6,5,0);
339 		case TextureFormat::UNORM_SHORT_4444:				return IVec4(4);
340 		case TextureFormat::UNORM_SHORT_555:				return IVec4(5,5,5,0);
341 		case TextureFormat::UNORM_SHORT_5551:				return IVec4(5,5,5,1);
342 		case TextureFormat::UNORM_INT_101010:				return IVec4(10,10,10,0);
343 		case TextureFormat::UNORM_INT_1010102_REV:			return IVec4(10,10,10,2);
344 		case TextureFormat::SIGNED_INT8:					return IVec4(8);
345 		case TextureFormat::SIGNED_INT16:					return IVec4(16);
346 		case TextureFormat::SIGNED_INT32:					return IVec4(32);
347 		case TextureFormat::UNSIGNED_INT8:					return IVec4(8);
348 		case TextureFormat::UNSIGNED_INT16:					return IVec4(16);
349 		case TextureFormat::UNSIGNED_INT24:					return IVec4(24);
350 		case TextureFormat::UNSIGNED_INT32:					return IVec4(32);
351 		case TextureFormat::UNSIGNED_INT_1010102_REV:		return IVec4(10,10,10,2);
352 		case TextureFormat::UNSIGNED_INT_24_8:				return IVec4(24,8,0,0);
353 		case TextureFormat::HALF_FLOAT:						return IVec4(16);
354 		case TextureFormat::FLOAT:							return IVec4(32);
355 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(11,11,10,0);
356 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return IVec4(9,9,9,0);
357 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(32,8,0,0);
358 		default:
359 			DE_ASSERT(false);
360 			return IVec4(0);
361 	}
362 }
363 
getTextureFormatBitDepth(const TextureFormat & format)364 IVec4 getTextureFormatBitDepth (const TextureFormat& format)
365 {
366 	const IVec4						chnBits		= getChannelBitDepth(format.type);
367 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
368 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
369 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
370 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
371 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
372 	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
373 														(chnMask[1]) ? ((int)map[1]) : (0),
374 														(chnMask[2]) ? ((int)map[2]) : (0),
375 														(chnMask[3]) ? ((int)map[3]) : (0));
376 
377 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
378 }
379 
getChannelMantissaBitDepth(TextureFormat::ChannelType channelType)380 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
381 {
382 	// make sure this table is updated if format table is updated
383 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
384 
385 	switch (channelType)
386 	{
387 		case TextureFormat::SNORM_INT8:
388 		case TextureFormat::SNORM_INT16:
389 		case TextureFormat::SNORM_INT32:
390 		case TextureFormat::UNORM_INT8:
391 		case TextureFormat::UNORM_INT16:
392 		case TextureFormat::UNORM_INT24:
393 		case TextureFormat::UNORM_INT32:
394 		case TextureFormat::UNORM_SHORT_565:
395 		case TextureFormat::UNORM_SHORT_4444:
396 		case TextureFormat::UNORM_SHORT_555:
397 		case TextureFormat::UNORM_SHORT_5551:
398 		case TextureFormat::UNORM_INT_101010:
399 		case TextureFormat::UNORM_INT_1010102_REV:
400 		case TextureFormat::SIGNED_INT8:
401 		case TextureFormat::SIGNED_INT16:
402 		case TextureFormat::SIGNED_INT32:
403 		case TextureFormat::UNSIGNED_INT8:
404 		case TextureFormat::UNSIGNED_INT16:
405 		case TextureFormat::UNSIGNED_INT24:
406 		case TextureFormat::UNSIGNED_INT32:
407 		case TextureFormat::UNSIGNED_INT_1010102_REV:
408 		case TextureFormat::UNSIGNED_INT_24_8:
409 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
410 			return getChannelBitDepth(channelType);
411 
412 		case TextureFormat::HALF_FLOAT:						return IVec4(10);
413 		case TextureFormat::FLOAT:							return IVec4(23);
414 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(6,6,5,0);
415 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(23,8,0,0);
416 		default:
417 			DE_ASSERT(false);
418 			return IVec4(0);
419 	}
420 }
421 
getTextureFormatMantissaBitDepth(const TextureFormat & format)422 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
423 {
424 	const IVec4						chnBits		= getChannelMantissaBitDepth(format.type);
425 	const TextureSwizzle::Channel*	map			= getChannelReadSwizzle(format.order).components;
426 	const BVec4						chnMask		= BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
427 														deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
428 														deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
429 														deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
430 	const IVec4						chnSwz		= IVec4((chnMask[0]) ? ((int)map[0]) : (0),
431 														(chnMask[1]) ? ((int)map[1]) : (0),
432 														(chnMask[2]) ? ((int)map[2]) : (0),
433 														(chnMask[3]) ? ((int)map[3]) : (0));
434 
435 	return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
436 }
437 
getTextureFormatChannelMask(const TextureFormat & format)438 BVec4 getTextureFormatChannelMask (const TextureFormat& format)
439 {
440 	const TextureSwizzle::Channel* const map = getChannelReadSwizzle(format.order).components;
441 	return BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
442 				 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
443 				 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
444 				 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
445 }
446 
linearInterpolate(float t,float minVal,float maxVal)447 static inline float linearInterpolate (float t, float minVal, float maxVal)
448 {
449 	return minVal + (maxVal - minVal) * t;
450 }
451 
linearInterpolate(float t,const Vec4 & a,const Vec4 & b)452 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
453 {
454 	return a + (b - a) * t;
455 }
456 
457 enum
458 {
459 	CLEAR_OPTIMIZE_THRESHOLD		= 128,
460 	CLEAR_OPTIMIZE_MAX_PIXEL_SIZE	= 8
461 };
462 
fillRow(const PixelBufferAccess & dst,int y,int z,int pixelSize,const deUint8 * pixel)463 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
464 {
465 	DE_ASSERT(dst.getPixelPitch() == pixelSize); // only tightly packed
466 
467 	deUint8*	dstPtr	= (deUint8*)dst.getPixelPtr(0, y, z);
468 	int			width	= dst.getWidth();
469 
470 	if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize))
471 	{
472 		deUint64 val;
473 		memcpy(&val, pixel, sizeof(val));
474 
475 		for (int i = 0; i < width; i++)
476 			((deUint64*)dstPtr)[i] = val;
477 	}
478 	else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize))
479 	{
480 		deUint32 val;
481 		memcpy(&val, pixel, sizeof(val));
482 
483 		for (int i = 0; i < width; i++)
484 			((deUint32*)dstPtr)[i] = val;
485 	}
486 	else
487 	{
488 		for (int i = 0; i < width; i++)
489 			for (int j = 0; j < pixelSize; j++)
490 				dstPtr[i*pixelSize+j] = pixel[j];
491 	}
492 }
493 
clear(const PixelBufferAccess & access,const Vec4 & color)494 void clear (const PixelBufferAccess& access, const Vec4& color)
495 {
496 	const int	pixelSize				= access.getFormat().getPixelSize();
497 	const int	pixelPitch				= access.getPixelPitch();
498 	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
499 
500 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
501 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
502 	{
503 		// Convert to destination format.
504 		union
505 		{
506 			deUint8		u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
507 			deUint64	u64; // Forces 64-bit alignment.
508 		} pixel;
509 		DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
510 		PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
511 
512 		for (int z = 0; z < access.getDepth(); z++)
513 			for (int y = 0; y < access.getHeight(); y++)
514 				fillRow(access, y, z, pixelSize, &pixel.u8[0]);
515 	}
516 	else
517 	{
518 		for (int z = 0; z < access.getDepth(); z++)
519 			for (int y = 0; y < access.getHeight(); y++)
520 				for (int x = 0; x < access.getWidth(); x++)
521 					access.setPixel(color, x, y, z);
522 	}
523 }
524 
clear(const PixelBufferAccess & access,const IVec4 & color)525 void clear (const PixelBufferAccess& access, const IVec4& color)
526 {
527 	const int	pixelSize				= access.getFormat().getPixelSize();
528 	const int	pixelPitch				= access.getPixelPitch();
529 	const bool	rowPixelsTightlyPacked	= (pixelSize == pixelPitch);
530 
531 	if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
532 		pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
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]).setPixel(color, 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.setPixel(color, x, y, z);
553 	}
554 }
555 
clear(const PixelBufferAccess & access,const UVec4 & color)556 void clear (const PixelBufferAccess& access, const UVec4& color)
557 {
558 	clear(access, color.cast<deInt32>());
559 }
560 
clearDepth(const PixelBufferAccess & access,float depth)561 void clearDepth (const PixelBufferAccess& access, float depth)
562 {
563 	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::D);
564 
565 	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_DEPTH), tcu::Vec4(depth, 0.0f, 0.0f, 0.0f));
566 }
567 
clearStencil(const PixelBufferAccess & access,int stencil)568 void clearStencil (const PixelBufferAccess& access, int stencil)
569 {
570 	DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::S);
571 
572 	clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_STENCIL), tcu::UVec4(stencil, 0u, 0u, 0u));
573 }
574 
fillWithComponentGradients1D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)575 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
576 {
577 	DE_ASSERT(access.getHeight() == 1);
578 	for (int x = 0; x < access.getWidth(); x++)
579 	{
580 		float s = ((float)x + 0.5f) / (float)access.getWidth();
581 
582 		float r = linearInterpolate(s, minVal.x(), maxVal.x());
583 		float g = linearInterpolate(s, minVal.y(), maxVal.y());
584 		float b = linearInterpolate(s, minVal.z(), maxVal.z());
585 		float a = linearInterpolate(s, minVal.w(), maxVal.w());
586 
587 		access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
588 	}
589 }
590 
fillWithComponentGradients2D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)591 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
592 {
593 	for (int y = 0; y < access.getHeight(); y++)
594 	{
595 		for (int x = 0; x < access.getWidth(); x++)
596 		{
597 			float s = ((float)x + 0.5f) / (float)access.getWidth();
598 			float t = ((float)y + 0.5f) / (float)access.getHeight();
599 
600 			float r = linearInterpolate((      s  +       t) *0.5f, minVal.x(), maxVal.x());
601 			float g = linearInterpolate((      s  + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
602 			float b = linearInterpolate(((1.0f-s) +       t) *0.5f, minVal.z(), maxVal.z());
603 			float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
604 
605 			access.setPixel(tcu::Vec4(r, g, b, a), x, y);
606 		}
607 	}
608 }
609 
fillWithComponentGradients3D(const PixelBufferAccess & dst,const Vec4 & minVal,const Vec4 & maxVal)610 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal)
611 {
612 	for (int z = 0; z < dst.getDepth(); z++)
613 	{
614 		for (int y = 0; y < dst.getHeight(); y++)
615 		{
616 			for (int x = 0; x < dst.getWidth(); x++)
617 			{
618 				float s = ((float)x + 0.5f) / (float)dst.getWidth();
619 				float t = ((float)y + 0.5f) / (float)dst.getHeight();
620 				float p = ((float)z + 0.5f) / (float)dst.getDepth();
621 
622 				float r = linearInterpolate(s,						minVal.x(), maxVal.x());
623 				float g = linearInterpolate(t,						minVal.y(), maxVal.y());
624 				float b = linearInterpolate(p,						minVal.z(), maxVal.z());
625 				float a = linearInterpolate(1.0f - (s+t+p)/3.0f,	minVal.w(), maxVal.w());
626 
627 				dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
628 			}
629 		}
630 	}
631 }
632 
fillWithComponentGradients(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)633 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
634 {
635 	if (isCombinedDepthStencilType(access.getFormat().type))
636 	{
637 		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
638 		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
639 
640 		DE_ASSERT(hasDepth || hasStencil);
641 
642 		// For combined formats, treat D and S as separate channels
643 		if (hasDepth)
644 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal);
645 		if (hasStencil)
646 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0));
647 	}
648 	else
649 	{
650 		if (access.getHeight() == 1 && access.getDepth() == 1)
651 			fillWithComponentGradients1D(access, minVal, maxVal);
652 		else if (access.getDepth() == 1)
653 			fillWithComponentGradients2D(access, minVal, maxVal);
654 		else
655 			fillWithComponentGradients3D(access, minVal, maxVal);
656 	}
657 }
658 
fillWithGrid1D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)659 static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
660 {
661 	for (int x = 0; x < access.getWidth(); x++)
662 	{
663 		int mx = (x / cellSize) % 2;
664 
665 		if (mx)
666 			access.setPixel(colorB, x, 0);
667 		else
668 			access.setPixel(colorA, x, 0);
669 	}
670 }
671 
fillWithGrid2D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)672 static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
673 {
674 	for (int y = 0; y < access.getHeight(); y++)
675 	{
676 		for (int x = 0; x < access.getWidth(); x++)
677 		{
678 			int mx = (x / cellSize) % 2;
679 			int my = (y / cellSize) % 2;
680 
681 			if (mx ^ my)
682 				access.setPixel(colorB, x, y);
683 			else
684 				access.setPixel(colorA, x, y);
685 		}
686 	}
687 }
688 
fillWithGrid3D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)689 static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
690 {
691 	for (int z = 0; z < access.getDepth(); z++)
692 	{
693 		for (int y = 0; y < access.getHeight(); y++)
694 		{
695 			for (int x = 0; x < access.getWidth(); x++)
696 			{
697 				int mx = (x / cellSize) % 2;
698 				int my = (y / cellSize) % 2;
699 				int mz = (z / cellSize) % 2;
700 
701 				if (mx ^ my ^ mz)
702 					access.setPixel(colorB, x, y, z);
703 				else
704 					access.setPixel(colorA, x, y, z);
705 			}
706 		}
707 	}
708 }
709 
fillWithGrid(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)710 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
711 {
712 	if (isCombinedDepthStencilType(access.getFormat().type))
713 	{
714 		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
715 		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
716 
717 		DE_ASSERT(hasDepth || hasStencil);
718 
719 		// For combined formats, treat D and S as separate channels
720 		if (hasDepth)
721 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), colorA, colorB);
722 		if (hasStencil)
723 			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0));
724 	}
725 	else
726 	{
727 		if (access.getHeight() == 1 && access.getDepth() == 1)
728 			fillWithGrid1D(access, cellSize, colorA, colorB);
729 		else if (access.getDepth() == 1)
730 			fillWithGrid2D(access, cellSize, colorA, colorB);
731 		else
732 			fillWithGrid3D(access, cellSize, colorA, colorB);
733 	}
734 }
735 
fillWithRepeatableGradient(const PixelBufferAccess & access,const Vec4 & colorA,const Vec4 & colorB)736 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
737 {
738 	for (int y = 0; y < access.getHeight(); y++)
739 	{
740 		for (int x = 0; x < access.getWidth(); x++)
741 		{
742 			float s = ((float)x + 0.5f) / (float)access.getWidth();
743 			float t = ((float)y + 0.5f) / (float)access.getHeight();
744 
745 			float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
746 			float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
747 
748 			float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
749 			access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
750 		}
751 	}
752 }
753 
fillWithRGBAQuads(const PixelBufferAccess & dst)754 void fillWithRGBAQuads (const PixelBufferAccess& dst)
755 {
756 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
757 	int width	= dst.getWidth();
758 	int height	= dst.getHeight();
759 	int	left	= width/2;
760 	int top		= height/2;
761 
762 	clear(getSubregion(dst, 0,		0,		0, left,		top,		1),	Vec4(1.0f, 0.0f, 0.0f, 1.0f));
763 	clear(getSubregion(dst, left,	0,		0, width-left,	top,		1),	Vec4(0.0f, 1.0f, 0.0f, 1.0f));
764 	clear(getSubregion(dst, 0,		top,	0, left,		height-top,	1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
765 	clear(getSubregion(dst, left,	top,	0, width-left,	height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
766 }
767 
768 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
fillWithMetaballs(const PixelBufferAccess & dst,int numBalls,deUint32 seed)769 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
770 {
771 	TCU_CHECK_INTERNAL(dst.getDepth() == 1);
772 	std::vector<Vec2>	points(numBalls);
773 	de::Random			rnd(seed);
774 
775 	for (int i = 0; i < numBalls; i++)
776 	{
777 		float x = rnd.getFloat();
778 		float y = rnd.getFloat();
779 		points[i] = (Vec2(x, y));
780 	}
781 
782 	for (int y = 0; y < dst.getHeight(); y++)
783 	for (int x = 0; x < dst.getWidth(); x++)
784 	{
785 		Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
786 
787 		float sum = 0.0f;
788 		for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
789 		{
790 			Vec2	d = p - *i;
791 			float	f = 0.01f / (d.x()*d.x() + d.y()*d.y());
792 
793 			sum += f;
794 		}
795 
796 		dst.setPixel(Vec4(sum), x, y);
797 	}
798 }
799 
copy(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src)800 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src)
801 {
802 	DE_ASSERT(src.getSize() == dst.getSize());
803 
804 	const int	width				= dst.getWidth();
805 	const int	height				= dst.getHeight();
806 	const int	depth				= dst.getDepth();
807 
808 	const int	srcPixelSize		= src.getFormat().getPixelSize();
809 	const int	dstPixelSize		= dst.getFormat().getPixelSize();
810 	const int	srcPixelPitch		= src.getPixelPitch();
811 	const int	dstPixelPitch		= dst.getPixelPitch();
812 	const bool	srcTightlyPacked	= (srcPixelSize == srcPixelPitch);
813 	const bool	dstTightlyPacked	= (dstPixelSize == dstPixelPitch);
814 
815 	const bool	srcHasDepth			= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D);
816 	const bool	srcHasStencil		= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S);
817 	const bool	dstHasDepth			= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D);
818 	const bool	dstHasStencil		= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S);
819 
820 	if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked)
821 	{
822 		// Fast-path for matching formats.
823 		for (int z = 0; z < depth; z++)
824 		for (int y = 0; y < height; y++)
825 			deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width);
826 	}
827 	else if (src.getFormat() == dst.getFormat())
828 	{
829 		// Bit-exact copy for matching formats.
830 		for (int z = 0; z < depth; z++)
831 		for (int y = 0; y < height; y++)
832 		for (int x = 0; x < width; x++)
833 			deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize);
834 	}
835 	else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil)
836 	{
837 		DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel
838 
839 		if (dstHasDepth && srcHasDepth)
840 		{
841 			for (int z = 0; z < depth; z++)
842 			for (int y = 0; y < height; y++)
843 			for (int x = 0; x < width; x++)
844 				dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z);
845 		}
846 		else if (dstHasDepth && !srcHasDepth)
847 		{
848 			// consistency with color copies
849 			tcu::clearDepth(dst, 0.0f);
850 		}
851 
852 		if (dstHasStencil && srcHasStencil)
853 		{
854 			for (int z = 0; z < depth; z++)
855 			for (int y = 0; y < height; y++)
856 			for (int x = 0; x < width; x++)
857 				dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
858 		}
859 		else if (dstHasStencil && !srcHasStencil)
860 		{
861 			// consistency with color copies
862 			tcu::clearStencil(dst, 0u);
863 		}
864 	}
865 	else
866 	{
867 		TextureChannelClass		srcClass	= getTextureChannelClass(src.getFormat().type);
868 		TextureChannelClass		dstClass	= getTextureChannelClass(dst.getFormat().type);
869 		bool					srcIsInt	= srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
870 		bool					dstIsInt	= dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
871 
872 		if (srcIsInt && dstIsInt)
873 		{
874 			for (int z = 0; z < depth; z++)
875 			for (int y = 0; y < height; y++)
876 			for (int x = 0; x < width; x++)
877 				dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
878 		}
879 		else
880 		{
881 			for (int z = 0; z < depth; z++)
882 			for (int y = 0; y < height; y++)
883 			for (int x = 0; x < width; x++)
884 				dst.setPixel(src.getPixel(x, y, z), x, y, z);
885 		}
886 	}
887 }
888 
scale(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,Sampler::FilterMode filter)889 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
890 {
891 	DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
892 
893 	Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
894 					filter, filter, 0.0f, false);
895 
896 	float sX = (float)src.getWidth() / (float)dst.getWidth();
897 	float sY = (float)src.getHeight() / (float)dst.getHeight();
898 	float sZ = (float)src.getDepth() / (float)dst.getDepth();
899 
900 	if (dst.getDepth() == 1 && src.getDepth() == 1)
901 	{
902 		for (int y = 0; y < dst.getHeight(); y++)
903 		for (int x = 0; x < dst.getWidth(); x++)
904 			dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y);
905 	}
906 	else
907 	{
908 		for (int z = 0; z < dst.getDepth(); z++)
909 		for (int y = 0; y < dst.getHeight(); y++)
910 		for (int x = 0; x < dst.getWidth(); x++)
911 			dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z);
912 	}
913 }
914 
estimatePixelValueRange(const ConstPixelBufferAccess & access,Vec4 & minVal,Vec4 & maxVal)915 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
916 {
917 	const TextureFormat& format = access.getFormat();
918 
919 	switch (getTextureChannelClass(format.type))
920 	{
921 		case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
922 			// Normalized unsigned formats.
923 			minVal = Vec4(0.0f);
924 			maxVal = Vec4(1.0f);
925 			break;
926 
927 		case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
928 			// Normalized signed formats.
929 			minVal = Vec4(-1.0f);
930 			maxVal = Vec4(+1.0f);
931 			break;
932 
933 		default:
934 			// \note Samples every 4/8th pixel.
935 			minVal = Vec4(std::numeric_limits<float>::max());
936 			maxVal = Vec4(std::numeric_limits<float>::min());
937 
938 			for (int z = 0; z < access.getDepth(); z += 2)
939 			{
940 				for (int y = 0; y < access.getHeight(); y += 2)
941 				{
942 					for (int x = 0; x < access.getWidth(); x += 2)
943 					{
944 						Vec4 p = access.getPixel(x, y, z);
945 
946 						minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0]));
947 						minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1]));
948 						minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2]));
949 						minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3]));
950 
951 						maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0]));
952 						maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1]));
953 						maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2]));
954 						maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3]));
955 					}
956 				}
957 			}
958 			break;
959 	}
960 }
961 
computePixelScaleBias(const ConstPixelBufferAccess & access,Vec4 & scale,Vec4 & bias)962 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
963 {
964 	Vec4 minVal, maxVal;
965 	estimatePixelValueRange(access, minVal, maxVal);
966 
967 	const float eps = 0.0001f;
968 
969 	for (int c = 0; c < 4; c++)
970 	{
971 		if (maxVal[c] - minVal[c] < eps)
972 		{
973 			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
974 			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
975 		}
976 		else
977 		{
978 			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
979 			bias[c]		= 0.0f - minVal[c]*scale[c];
980 		}
981 	}
982 }
983 
getCubeArrayFaceIndex(CubeFace face)984 int getCubeArrayFaceIndex (CubeFace face)
985 {
986 	DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
987 
988 	switch (face)
989 	{
990 		case CUBEFACE_POSITIVE_X:	return 0;
991 		case CUBEFACE_NEGATIVE_X:	return 1;
992 		case CUBEFACE_POSITIVE_Y:	return 2;
993 		case CUBEFACE_NEGATIVE_Y:	return 3;
994 		case CUBEFACE_POSITIVE_Z:	return 4;
995 		case CUBEFACE_NEGATIVE_Z:	return 5;
996 
997 		default:
998 			return -1;
999 	}
1000 }
1001 
packRGB999E5(const tcu::Vec4 & color)1002 deUint32 packRGB999E5 (const tcu::Vec4& color)
1003 {
1004 	const int	mBits	= 9;
1005 	const int	eBits	= 5;
1006 	const int	eBias	= 15;
1007 	const int	eMax	= (1<<eBits)-1;
1008 	const float	maxVal	= (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits);
1009 
1010 	float	rc		= deFloatClamp(color[0], 0.0f, maxVal);
1011 	float	gc		= deFloatClamp(color[1], 0.0f, maxVal);
1012 	float	bc		= deFloatClamp(color[2], 0.0f, maxVal);
1013 	float	maxc	= de::max(rc, de::max(gc, bc));
1014 	int		expp	= de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias;
1015 	float	e		= deFloatPow(2.0f, (float)(expp-eBias-mBits));
1016 	int		maxs	= deFloorFloatToInt32(maxc / e + 0.5f);
1017 
1018 	deUint32	exps	= maxs == (1<<mBits) ? expp+1 : expp;
1019 	deUint32	rs		= (deUint32)deClamp32(deFloorFloatToInt32(rc / e + 0.5f), 0, (1<<9)-1);
1020 	deUint32	gs		= (deUint32)deClamp32(deFloorFloatToInt32(gc / e + 0.5f), 0, (1<<9)-1);
1021 	deUint32	bs		= (deUint32)deClamp32(deFloorFloatToInt32(bc / e + 0.5f), 0, (1<<9)-1);
1022 
1023 	DE_ASSERT((exps & ~((1<<5)-1)) == 0);
1024 	DE_ASSERT((rs & ~((1<<9)-1)) == 0);
1025 	DE_ASSERT((gs & ~((1<<9)-1)) == 0);
1026 	DE_ASSERT((bs & ~((1<<9)-1)) == 0);
1027 
1028 	return rs | (gs << 9) | (bs << 18) | (exps << 27);
1029 }
1030 
1031 // Sampler utils
1032 
addOffset(const void * ptr,int numBytes)1033 static const void* addOffset (const void* ptr, int numBytes)
1034 {
1035 	return (const deUint8*)ptr + numBytes;
1036 }
1037 
addOffset(void * ptr,int numBytes)1038 static void* addOffset (void* ptr, int numBytes)
1039 {
1040 	return (deUint8*)ptr + numBytes;
1041 }
1042 
1043 template <typename AccessType>
toSamplerAccess(const AccessType & baseAccess,Sampler::DepthStencilMode mode)1044 static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode)
1045 {
1046 	// make sure to update this if type table is updated
1047 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27);
1048 
1049 	if (!isCombinedDepthStencilType(baseAccess.getFormat().type))
1050 		return baseAccess;
1051 	else
1052 	{
1053 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
1054 		const deUint32 uint32ByteOffsetBits0To8	= 0; //!< least significant byte in the lowest address
1055 		const deUint32 uint32ByteOffset8To32	= 1;
1056 #else
1057 		const deUint32 uint32ByteOffsetBits0To8	= 3; //!< least significant byte in the highest address
1058 		const deUint32 uint32ByteOffset8To32	= 0;
1059 #endif
1060 
1061 		// Sampled channel must exist
1062 		DE_ASSERT(baseAccess.getFormat().order == TextureFormat::DS ||
1063 				  (mode == Sampler::MODE_DEPTH && baseAccess.getFormat().order == TextureFormat::D) ||
1064 				  (mode == Sampler::MODE_STENCIL && baseAccess.getFormat().order == TextureFormat::S));
1065 
1066 		// combined formats have multiple channel classes, detect on sampler settings
1067 		switch (baseAccess.getFormat().type)
1068 		{
1069 			case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1070 			{
1071 				if (mode == Sampler::MODE_DEPTH)
1072 				{
1073 					// select the float component
1074 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::FLOAT),
1075 									  baseAccess.getSize(),
1076 									  baseAccess.getPitch(),
1077 									  baseAccess.getDataPtr());
1078 				}
1079 				else if (mode == Sampler::MODE_STENCIL)
1080 				{
1081 					// select the uint 8 component
1082 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1083 									  baseAccess.getSize(),
1084 									  baseAccess.getPitch(),
1085 									  addOffset(baseAccess.getDataPtr(), 4 + uint32ByteOffsetBits0To8));
1086 				}
1087 				else
1088 				{
1089 					// unknown sampler mode
1090 					DE_ASSERT(false);
1091 					return AccessType();
1092 				}
1093 			}
1094 
1095 			case TextureFormat::UNSIGNED_INT_24_8:
1096 			{
1097 				if (mode == Sampler::MODE_DEPTH)
1098 				{
1099 					// select the unorm24 component
1100 					return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
1101 									  baseAccess.getSize(),
1102 									  baseAccess.getPitch(),
1103 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffset8To32));
1104 				}
1105 				else if (mode == Sampler::MODE_STENCIL)
1106 				{
1107 					// select the uint 8 component
1108 					return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1109 									  baseAccess.getSize(),
1110 									  baseAccess.getPitch(),
1111 									  addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
1112 				}
1113 				else
1114 				{
1115 					// unknown sampler mode
1116 					DE_ASSERT(false);
1117 					return AccessType();
1118 				}
1119 			}
1120 
1121 			default:
1122 			{
1123 				// unknown combined format
1124 				DE_ASSERT(false);
1125 				return AccessType();
1126 			}
1127 		}
1128 	}
1129 }
1130 
getEffectiveDepthStencilAccess(const PixelBufferAccess & baseAccess,Sampler::DepthStencilMode mode)1131 PixelBufferAccess getEffectiveDepthStencilAccess (const PixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1132 {
1133 	return toSamplerAccess<PixelBufferAccess>(baseAccess, mode);
1134 }
1135 
getEffectiveDepthStencilAccess(const ConstPixelBufferAccess & baseAccess,Sampler::DepthStencilMode mode)1136 ConstPixelBufferAccess getEffectiveDepthStencilAccess (const ConstPixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1137 {
1138 	return toSamplerAccess<ConstPixelBufferAccess>(baseAccess, mode);
1139 }
1140 
getEffectiveDepthStencilTextureFormat(const TextureFormat & baseFormat,Sampler::DepthStencilMode mode)1141 TextureFormat getEffectiveDepthStencilTextureFormat (const TextureFormat& baseFormat, Sampler::DepthStencilMode mode)
1142 {
1143 	return toSamplerAccess(ConstPixelBufferAccess(baseFormat, IVec3(0, 0, 0), DE_NULL), mode).getFormat();
1144 }
1145 
1146 template <typename ViewType>
getEffectiveTView(const ViewType & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1147 ViewType getEffectiveTView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1148 {
1149 	storage.resize(src.getNumLevels());
1150 
1151 	ViewType view = ViewType(src.getNumLevels(), &storage[0]);
1152 
1153 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1154 		storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode);
1155 
1156 	return view;
1157 }
1158 
getEffectiveTView(const tcu::TextureCubeView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1159 tcu::TextureCubeView getEffectiveTView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1160 {
1161 	storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels());
1162 
1163 	const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] =
1164 	{
1165 		&storage[0 * src.getNumLevels()],
1166 		&storage[1 * src.getNumLevels()],
1167 		&storage[2 * src.getNumLevels()],
1168 		&storage[3 * src.getNumLevels()],
1169 		&storage[4 * src.getNumLevels()],
1170 		&storage[5 * src.getNumLevels()],
1171 	};
1172 
1173 	tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs);
1174 
1175 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1176 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1177 		storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode);
1178 
1179 	return view;
1180 }
1181 
getEffectiveTextureView(const tcu::Texture1DView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1182 tcu::Texture1DView getEffectiveTextureView (const tcu::Texture1DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1183 {
1184 	return getEffectiveTView(src, storage, sampler);
1185 }
1186 
getEffectiveTextureView(const tcu::Texture2DView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1187 tcu::Texture2DView getEffectiveTextureView (const tcu::Texture2DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1188 {
1189 	return getEffectiveTView(src, storage, sampler);
1190 }
1191 
getEffectiveTextureView(const tcu::Texture3DView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1192 tcu::Texture3DView getEffectiveTextureView (const tcu::Texture3DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1193 {
1194 	return getEffectiveTView(src, storage, sampler);
1195 }
1196 
getEffectiveTextureView(const tcu::Texture1DArrayView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1197 tcu::Texture1DArrayView getEffectiveTextureView (const tcu::Texture1DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1198 {
1199 	return getEffectiveTView(src, storage, sampler);
1200 }
1201 
getEffectiveTextureView(const tcu::Texture2DArrayView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1202 tcu::Texture2DArrayView getEffectiveTextureView (const tcu::Texture2DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1203 {
1204 	return getEffectiveTView(src, storage, sampler);
1205 }
1206 
getEffectiveTextureView(const tcu::TextureCubeView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1207 tcu::TextureCubeView getEffectiveTextureView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1208 {
1209 	return getEffectiveTView(src, storage, sampler);
1210 }
1211 
getEffectiveTextureView(const tcu::TextureCubeArrayView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1212 tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1213 {
1214 	return getEffectiveTView(src, storage, sampler);
1215 }
1216 
1217 //! Returns the effective swizzle of a border color. The effective swizzle is the
1218 //! equal to first writing an RGBA color with a write swizzle and then reading
1219 //! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
getBorderColorReadSwizzle(TextureFormat::ChannelOrder order)1220 static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order)
1221 {
1222 	// make sure to update these tables when channel orders are updated
1223 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 18);
1224 
1225 	static const TextureSwizzle INV		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1226 	static const TextureSwizzle R		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1227 	static const TextureSwizzle A		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
1228 	static const TextureSwizzle I		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0	}};
1229 	static const TextureSwizzle L		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ONE	}};
1230 	static const TextureSwizzle LA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3	}};
1231 	static const TextureSwizzle RG		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1232 	static const TextureSwizzle RA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_3	}};
1233 	static const TextureSwizzle RGB		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_ONE	}};
1234 	static const TextureSwizzle RGBA	= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3	}};
1235 	static const TextureSwizzle D		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1236 	static const TextureSwizzle S		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
1237 
1238 	const TextureSwizzle* swizzle;
1239 
1240 	switch (order)
1241 	{
1242 		case TextureFormat::R:			swizzle = &R;		break;
1243 		case TextureFormat::A:			swizzle = &A;		break;
1244 		case TextureFormat::I:			swizzle = &I;		break;
1245 		case TextureFormat::L:			swizzle = &L;		break;
1246 		case TextureFormat::LA:			swizzle = &LA;		break;
1247 		case TextureFormat::RG:			swizzle = &RG;		break;
1248 		case TextureFormat::RA:			swizzle = &RA;		break;
1249 		case TextureFormat::RGB:		swizzle = &RGB;		break;
1250 		case TextureFormat::RGBA:		swizzle = &RGBA;	break;
1251 		case TextureFormat::ARGB:		swizzle = &RGBA;	break;
1252 		case TextureFormat::BGRA:		swizzle = &RGBA;	break;
1253 		case TextureFormat::sR:			swizzle = &R;		break;
1254 		case TextureFormat::sRG:		swizzle = &RG;		break;
1255 		case TextureFormat::sRGB:		swizzle = &RGB;		break;
1256 		case TextureFormat::sRGBA:		swizzle = &RGBA;	break;
1257 		case TextureFormat::D:			swizzle = &D;		break;
1258 		case TextureFormat::S:			swizzle = &S;		break;
1259 
1260 		case TextureFormat::DS:
1261 			DE_ASSERT(false); // combined depth-stencil border color?
1262 			swizzle = &INV;
1263 			break;
1264 
1265 		default:
1266 			DE_ASSERT(false);
1267 			swizzle = &INV;
1268 			break;
1269 	}
1270 
1271 #ifdef DE_DEBUG
1272 
1273 	{
1274 		// check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
1275 		const TextureSwizzle& readSwizzle	= getChannelReadSwizzle(order);
1276 		const TextureSwizzle& writeSwizzle	= getChannelWriteSwizzle(order);
1277 
1278 		for (int ndx = 0; ndx < 4; ++ndx)
1279 		{
1280 			TextureSwizzle::Channel writeRead = readSwizzle.components[ndx];
1281 			if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE)
1282 				writeRead = writeSwizzle.components[(int)writeRead];
1283 			DE_ASSERT(writeRead == swizzle->components[ndx]);
1284 		}
1285 	}
1286 
1287 #endif
1288 
1289 	return *swizzle;
1290 }
1291 
getNBitUnsignedIntegerVec4MaxValue(const tcu::IVec4 & numBits)1292 static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1293 {
1294 	return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0),
1295 					  (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0),
1296 					  (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0),
1297 					  (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0));
1298 }
1299 
getNBitSignedIntegerVec4MaxValue(const tcu::IVec4 & numBits)1300 static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1301 {
1302 	return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0),
1303 					  (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0),
1304 					  (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0),
1305 					  (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0));
1306 }
1307 
getNBitSignedIntegerVec4MinValue(const tcu::IVec4 & numBits)1308 static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits)
1309 {
1310 	return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0),
1311 					  (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0),
1312 					  (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0),
1313 					  (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0));
1314 }
1315 
getTextureBorderColorFloat(const TextureFormat & format,const Sampler & sampler)1316 static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler)
1317 {
1318 	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
1319 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1320 	const bool						isFloat			= channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1321 	const bool						isSigned		= channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1322 	const float						valueMin		= (isSigned) ? (-1.0f) : (0.0f);
1323 	const float						valueMax		= 1.0f;
1324 	Vec4							result;
1325 
1326 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
1327 			  channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1328 			  channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
1329 
1330 	for (int c = 0; c < 4; c++)
1331 	{
1332 		const TextureSwizzle::Channel map = channelMap[c];
1333 		if (map == TextureSwizzle::CHANNEL_ZERO)
1334 			result[c] = 0.0f;
1335 		else if (map == TextureSwizzle::CHANNEL_ONE)
1336 			result[c] = 1.0f;
1337 		else if (isFloat)
1338 		{
1339 			// floating point values are not clamped
1340 			result[c] = sampler.borderColor.getAccess<float>()[(int)map];
1341 		}
1342 		else
1343 		{
1344 			// fixed point values are clamped to a representable range
1345 			result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax);
1346 		}
1347 	}
1348 
1349 	return result;
1350 }
1351 
getTextureBorderColorInt(const TextureFormat & format,const Sampler & sampler)1352 static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler)
1353 {
1354 	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
1355 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1356 	const IVec4						channelBits		= getChannelBitDepth(format.type);
1357 	const IVec4						valueMin		= getNBitSignedIntegerVec4MinValue(channelBits);
1358 	const IVec4						valueMax		= getNBitSignedIntegerVec4MaxValue(channelBits);
1359 	IVec4							result;
1360 
1361 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
1362 	DE_UNREF(channelClass);
1363 
1364 	for (int c = 0; c < 4; c++)
1365 	{
1366 		const TextureSwizzle::Channel map = channelMap[c];
1367 		if (map == TextureSwizzle::CHANNEL_ZERO)
1368 			result[c] = 0;
1369 		else if (map == TextureSwizzle::CHANNEL_ONE)
1370 			result[c] = 1;
1371 		else
1372 		{
1373 			// integer values are clamped to a representable range
1374 			result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]);
1375 		}
1376 	}
1377 
1378 	return result;
1379 }
1380 
getTextureBorderColorUint(const TextureFormat & format,const Sampler & sampler)1381 static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler)
1382 {
1383 	const tcu::TextureChannelClass	channelClass 	= getTextureChannelClass(format.type);
1384 	const TextureSwizzle::Channel*	channelMap		= getBorderColorReadSwizzle(format.order).components;
1385 	const IVec4						channelBits		= getChannelBitDepth(format.type);
1386 	const UVec4						valueMax		= getNBitUnsignedIntegerVec4MaxValue(channelBits);
1387 	UVec4							result;
1388 
1389 	DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
1390 	DE_UNREF(channelClass);
1391 
1392 	for (int c = 0; c < 4; c++)
1393 	{
1394 		const TextureSwizzle::Channel map = channelMap[c];
1395 		if (map == TextureSwizzle::CHANNEL_ZERO)
1396 			result[c] = 0;
1397 		else if (map == TextureSwizzle::CHANNEL_ONE)
1398 			result[c] = 1;
1399 		else
1400 		{
1401 			// integer values are clamped to a representable range
1402 			result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]);
1403 		}
1404 	}
1405 
1406 	return result;
1407 }
1408 
1409 template <typename ScalarType>
sampleTextureBorder(const TextureFormat & format,const Sampler & sampler)1410 tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler)
1411 {
1412 	const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1413 
1414 	switch (channelClass)
1415 	{
1416 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1417 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1418 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1419 			return getTextureBorderColorFloat(format, sampler).cast<ScalarType>();
1420 
1421 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1422 			return getTextureBorderColorInt(format, sampler).cast<ScalarType>();
1423 
1424 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1425 			return getTextureBorderColorUint(format, sampler).cast<ScalarType>();
1426 
1427 		default:
1428 			DE_ASSERT(false);
1429 			return tcu::Vector<ScalarType, 4>();
1430 	}
1431 }
1432 
1433 // instantiation
1434 template tcu::Vector<float, 4>		sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1435 template tcu::Vector<deInt32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1436 template tcu::Vector<deUint32, 4>	sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1437 
1438 } // tcu
1439