• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Reference Texture Implementation.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuTexture.hpp"
25 #include "deInt32.h"
26 #include "deFloat16.h"
27 #include "deMath.h"
28 #include "deMemory.h"
29 #include "tcuTestLog.hpp"
30 #include "tcuSurface.hpp"
31 #include "tcuFloat.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "deStringUtil.hpp"
34 #include "deArrayUtil.hpp"
35 #include "tcuMatrix.hpp"
36 
37 #include <limits>
38 
39 namespace tcu
40 {
41 
42 // \note No sign. Denorms are supported.
43 typedef Float<deUint32, 5, 6, 15, FLOAT_SUPPORT_DENORM>	Float11;
44 typedef Float<deUint32, 5, 5, 15, FLOAT_SUPPORT_DENORM>	Float10;
45 
46 namespace
47 {
48 
49 // Optimized getters for common formats.
50 // \todo [2012-11-14 pyry] Use intrinsics if available.
51 
readRGBA8888Float(const deUint8 * ptr)52 inline Vec4		readRGBA8888Float	(const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, ptr[3]/255.0f); }
readRGB888Float(const deUint8 * ptr)53 inline Vec4		readRGB888Float		(const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, 1.0f); }
readRGBA8888Int(const deUint8 * ptr)54 inline IVec4	readRGBA8888Int		(const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], ptr[3]); }
readRGB888Int(const deUint8 * ptr)55 inline IVec4	readRGB888Int		(const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], 1); }
56 
57 // Optimized setters.
58 
writeRGBA8888Int(deUint8 * ptr,const IVec4 & val)59 inline void writeRGBA8888Int (deUint8* ptr, const IVec4& val)
60 {
61 	ptr[0] = (deUint8)de::clamp(val[0], 0, 255);
62 	ptr[1] = (deUint8)de::clamp(val[1], 0, 255);
63 	ptr[2] = (deUint8)de::clamp(val[2], 0, 255);
64 	ptr[3] = (deUint8)de::clamp(val[3], 0, 255);
65 }
66 
writeRGB888Int(deUint8 * ptr,const IVec4 & val)67 inline void writeRGB888Int (deUint8* ptr, const IVec4& val)
68 {
69 	ptr[0] = (deUint8)de::clamp(val[0], 0, 255);
70 	ptr[1] = (deUint8)de::clamp(val[1], 0, 255);
71 	ptr[2] = (deUint8)de::clamp(val[2], 0, 255);
72 }
73 
writeRGBA8888Float(deUint8 * ptr,const Vec4 & val)74 inline void writeRGBA8888Float (deUint8* ptr, const Vec4& val)
75 {
76 	ptr[0] = floatToU8(val[0]);
77 	ptr[1] = floatToU8(val[1]);
78 	ptr[2] = floatToU8(val[2]);
79 	ptr[3] = floatToU8(val[3]);
80 }
81 
writeRGB888Float(deUint8 * ptr,const Vec4 & val)82 inline void writeRGB888Float (deUint8* ptr, const Vec4& val)
83 {
84 	ptr[0] = floatToU8(val[0]);
85 	ptr[1] = floatToU8(val[1]);
86 	ptr[2] = floatToU8(val[2]);
87 }
88 
writeUint24(deUint8 * dst,deUint32 val)89 inline void writeUint24 (deUint8* dst, deUint32 val)
90 {
91 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
92 	dst[0] = (deUint8)((val & 0x0000FFu) >>  0u);
93 	dst[1] = (deUint8)((val & 0x00FF00u) >>  8u);
94 	dst[2] = (deUint8)((val & 0xFF0000u) >> 16u);
95 #else
96 	dst[0] = (deUint8)((val & 0xFF0000u) >> 16u);
97 	dst[1] = (deUint8)((val & 0x00FF00u) >>  8u);
98 	dst[2] = (deUint8)((val & 0x0000FFu) >>  0u);
99 #endif
100 }
101 
readUint24(const deUint8 * src)102 inline deUint32 readUint24 (const deUint8* src)
103 {
104 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
105 	return	(((deUint32)src[0]) <<  0u) |
106 			(((deUint32)src[1]) <<  8u) |
107 			(((deUint32)src[2]) << 16u);
108 #else
109 	return	(((deUint32)src[0]) << 16u) |
110 			(((deUint32)src[1]) <<  8u) |
111 			(((deUint32)src[2]) <<  0u);
112 #endif
113 }
114 
readUint32Low8(const deUint8 * src)115 inline deUint8 readUint32Low8 (const deUint8* src)
116 {
117 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
118 	const deUint32 uint32ByteOffsetBits0To8	= 0; //!< least significant byte in the lowest address
119 #else
120 	const deUint32 uint32ByteOffsetBits0To8	= 3; //!< least significant byte in the highest address
121 #endif
122 
123 	return src[uint32ByteOffsetBits0To8];
124 }
125 
readUint32High8(const deUint8 * src)126 inline deUint8 readUint32High8 (const deUint8* src)
127 {
128 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
129 	const deUint32 uint32ByteOffsetBits24To32	= 3;
130 #else
131 	const deUint32 uint32ByteOffsetBits24To32	= 0;
132 #endif
133 
134 	return src[uint32ByteOffsetBits24To32];
135 }
136 
writeUint32Low8(deUint8 * dst,deUint8 val)137 inline void writeUint32Low8 (deUint8* dst, deUint8 val)
138 {
139 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
140 	const deUint32 uint32ByteOffsetBits0To8	= 0; //!< least significant byte in the lowest address
141 #else
142 	const deUint32 uint32ByteOffsetBits0To8	= 3; //!< least significant byte in the highest address
143 #endif
144 
145 	dst[uint32ByteOffsetBits0To8] = val;
146 }
147 
writeUint32High8(deUint8 * dst,deUint8 val)148 inline void writeUint32High8 (deUint8* dst, deUint8 val)
149 {
150 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
151 	const deUint32 uint32ByteOffsetBits24To32	= 3;
152 #else
153 	const deUint32 uint32ByteOffsetBits24To32	= 0;
154 #endif
155 
156 	dst[uint32ByteOffsetBits24To32] = val;
157 }
158 
readUint32High16(const deUint8 * src)159 inline deUint32 readUint32High16 (const deUint8* src)
160 {
161 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
162 	const deUint32 uint32ByteOffset16To32	= 2;
163 #else
164 	const deUint32 uint32ByteOffset16To32	= 0;
165 #endif
166 
167 	return *(const deUint16*)(src + uint32ByteOffset16To32);
168 }
169 
writeUint32High16(deUint8 * dst,deUint16 val)170 inline void writeUint32High16 (deUint8* dst, deUint16 val)
171 {
172 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
173 	const deUint32 uint32ByteOffset16To32	= 2;
174 #else
175 	const deUint32 uint32ByteOffset16To32	= 0;
176 #endif
177 
178 	*(deUint16*)(dst + uint32ByteOffset16To32) = val;
179 }
180 
readUint32Low24(const deUint8 * src)181 inline deUint32 readUint32Low24 (const deUint8* src)
182 {
183 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
184 	const deUint32 uint32ByteOffset0To24	= 0;
185 #else
186 	const deUint32 uint32ByteOffset0To24	= 1;
187 #endif
188 
189 	return readUint24(src + uint32ByteOffset0To24);
190 }
191 
readUint32High24(const deUint8 * src)192 inline deUint32 readUint32High24 (const deUint8* src)
193 {
194 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
195 	const deUint32 uint32ByteOffset8To32	= 1;
196 #else
197 	const deUint32 uint32ByteOffset8To32	= 0;
198 #endif
199 
200 	return readUint24(src + uint32ByteOffset8To32);
201 }
202 
writeUint32Low24(deUint8 * dst,deUint32 val)203 inline void writeUint32Low24 (deUint8* dst, deUint32 val)
204 {
205 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
206 	const deUint32 uint32ByteOffset0To24	= 0;
207 #else
208 	const deUint32 uint32ByteOffset0To24	= 1;
209 #endif
210 
211 	writeUint24(dst + uint32ByteOffset0To24, val);
212 }
213 
writeUint32High24(deUint8 * dst,deUint32 val)214 inline void writeUint32High24 (deUint8* dst, deUint32 val)
215 {
216 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
217 	const deUint32 uint32ByteOffset8To32	= 1;
218 #else
219 	const deUint32 uint32ByteOffset8To32	= 0;
220 #endif
221 
222 	writeUint24(dst + uint32ByteOffset8To32, val);
223 }
224 
225 // \todo [2011-09-21 pyry] Move to tcutil?
226 template <typename T>
convertSatRte(float f)227 inline T convertSatRte (float f)
228 {
229 	// \note Doesn't work for 64-bit types
230 	DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
231 	DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
232 
233 	deInt64	minVal	= std::numeric_limits<T>::min();
234 	deInt64 maxVal	= std::numeric_limits<T>::max();
235 	float	q		= deFloatFrac(f);
236 	deInt64 intVal	= (deInt64)(f-q);
237 
238 	// Rounding.
239 	if (q == 0.5f)
240 	{
241 		if (intVal % 2 != 0)
242 			intVal++;
243 	}
244 	else if (q > 0.5f)
245 		intVal++;
246 	// else Don't add anything
247 
248 	// Saturate.
249 	intVal = de::max(minVal, de::min(maxVal, intVal));
250 
251 	return (T)intVal;
252 }
253 
convertSatRteUint24(float f)254 inline deUint32 convertSatRteUint24 (float f)
255 {
256 	const deUint32 rounded		= convertSatRte<deUint32>(f);
257 	const deUint32 maxUint24	= 0xFFFFFFu;
258 	return de::min(rounded, maxUint24);
259 }
260 
convertSatRteUint10(float f)261 inline deUint16 convertSatRteUint10 (float f)
262 {
263 	const deUint16 rounded		= convertSatRte<deUint16>(f);
264 	const deUint16 maxUint10	= 0x3FFu;
265 	return de::min(rounded, maxUint10);
266 }
267 
convertSatRteUint12(float f)268 inline deUint16 convertSatRteUint12 (float f)
269 {
270 	const deUint16 rounded		= convertSatRte<deUint16>(f);
271 	const deUint16 maxUint12	= 0xFFFu;
272 	return de::min(rounded, maxUint12);
273 }
274 
channelToFloat(const deUint8 * value,TextureFormat::ChannelType type)275 inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
276 {
277 	// make sure this table is updated if format table is updated
278 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
279 
280 	switch (type)
281 	{
282 		case TextureFormat::SNORM_INT8:			return de::max(-1.0f, (float)*((const deInt8*)value) / 127.0f);
283 		case TextureFormat::SNORM_INT16:		return de::max(-1.0f, (float)*((const deInt16*)value) / 32767.0f);
284 		case TextureFormat::SNORM_INT32:		return de::max(-1.0f, (float)*((const deInt32*)value) / 2147483647.0f);
285 		case TextureFormat::UNORM_INT8:			return (float)*((const deUint8*)value) / 255.0f;
286 		case TextureFormat::UNORM_INT16:		return (float)*((const deUint16*)value) / 65535.0f;
287 		case TextureFormat::UNORM_INT24:		return (float)readUint24(value) / 16777215.0f;
288 		case TextureFormat::UNORM_INT32:		return (float)*((const deUint32*)value) / 4294967295.0f;
289 		case TextureFormat::SIGNED_INT8:		return (float)*((const deInt8*)value);
290 		case TextureFormat::SIGNED_INT16:		return (float)*((const deInt16*)value);
291 		case TextureFormat::SIGNED_INT32:		return (float)*((const deInt32*)value);
292 		case TextureFormat::SIGNED_INT64:		return (float)*((const deInt64*)value);
293 		case TextureFormat::UNSIGNED_INT8:		return (float)*((const deUint8*)value);
294 		case TextureFormat::UNSIGNED_INT16:		return (float)*((const deUint16*)value);
295 		case TextureFormat::UNSIGNED_INT24:		return (float)readUint24(value);
296 		case TextureFormat::UNSIGNED_INT32:		return (float)*((const deUint32*)value);
297 		case TextureFormat::UNSIGNED_INT64:		return (float)*((const deUint64*)value);
298 		case TextureFormat::HALF_FLOAT:			return deFloat16To32(*(const deFloat16*)value);
299 		case TextureFormat::FLOAT:				return *((const float*)value);
300 		case TextureFormat::FLOAT64:			return (float)*((const double*)value);
301 		case TextureFormat::UNORM_SHORT_10:		return (float)((*((const deUint16*)value)) >> 6u) / 1023.0f;
302 		case TextureFormat::UNORM_SHORT_12:		return (float)((*((const deUint16*)value)) >> 4u) / 4095.0f;
303 		case TextureFormat::USCALED_INT8:		return (float)*((const deUint8*)value);
304 		case TextureFormat::USCALED_INT16:		return (float)*((const deUint16*)value);
305 		case TextureFormat::SSCALED_INT8:		return (float)*((const deInt8*)value);
306 		case TextureFormat::SSCALED_INT16:		return (float)*((const deInt16*)value);
307 		default:
308 			DE_ASSERT(DE_FALSE);
309 			return 0.0f;
310 	}
311 }
312 
313 template <class T>
channelToIntType(const deUint8 * value,TextureFormat::ChannelType type)314 inline T channelToIntType (const deUint8* value, TextureFormat::ChannelType type)
315 {
316 	// make sure this table is updated if format table is updated
317 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
318 
319 	switch (type)
320 	{
321 		case TextureFormat::SNORM_INT8:			return (T)*((const deInt8*)value);
322 		case TextureFormat::SNORM_INT16:		return (T)*((const deInt16*)value);
323 		case TextureFormat::SNORM_INT32:		return (T)*((const deInt32*)value);
324 		case TextureFormat::UNORM_INT8:			return (T)*((const deUint8*)value);
325 		case TextureFormat::UNORM_INT16:		return (T)*((const deUint16*)value);
326 		case TextureFormat::UNORM_INT24:		return (T)readUint24(value);
327 		case TextureFormat::UNORM_INT32:		return (T)*((const deUint32*)value);
328 		case TextureFormat::SIGNED_INT8:		return (T)*((const deInt8*)value);
329 		case TextureFormat::SIGNED_INT16:		return (T)*((const deInt16*)value);
330 		case TextureFormat::SIGNED_INT32:		return (T)*((const deInt32*)value);
331 		case TextureFormat::SIGNED_INT64:		return (T)*((const deInt64*)value);
332 		case TextureFormat::UNSIGNED_INT8:		return (T)*((const deUint8*)value);
333 		case TextureFormat::UNSIGNED_INT16:		return (T)*((const deUint16*)value);
334 		case TextureFormat::UNSIGNED_INT24:		return (T)readUint24(value);
335 		case TextureFormat::UNSIGNED_INT32:		return (T)*((const deUint32*)value);
336 		case TextureFormat::UNSIGNED_INT64:		return (T)*((const deUint64*)value);
337 		case TextureFormat::HALF_FLOAT:			return (T)deFloat16To32(*(const deFloat16*)value);
338 		case TextureFormat::FLOAT:				return (T)*((const float*)value);
339 		case TextureFormat::FLOAT64:			return (T)*((const double*)value);
340 		case TextureFormat::UNORM_SHORT_10:		return (T)((*(((const deUint16*)value))) >> 6u);
341 		case TextureFormat::UNORM_SHORT_12:		return (T)((*(((const deUint16*)value))) >> 4u);
342 		case TextureFormat::USCALED_INT8:		return (T)*((const deUint8*)value);
343 		case TextureFormat::USCALED_INT16:		return (T)*((const deUint16*)value);
344 		case TextureFormat::SSCALED_INT8:		return (T)*((const deInt8*)value);
345 		case TextureFormat::SSCALED_INT16:		return (T)*((const deInt16*)value);
346 		default:
347 			DE_ASSERT(DE_FALSE);
348 			return 0;
349 	}
350 }
351 
channelToInt(const deUint8 * value,TextureFormat::ChannelType type)352 inline int channelToInt (const deUint8* value, TextureFormat::ChannelType type)
353 {
354 	return channelToIntType<int>(value, type);
355 }
356 
floatToChannel(deUint8 * dst,float src,TextureFormat::ChannelType type)357 void floatToChannel (deUint8* dst, float src, TextureFormat::ChannelType type)
358 {
359 	// make sure this table is updated if format table is updated
360 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
361 
362 	switch (type)
363 	{
364 		case TextureFormat::SNORM_INT8:			*((deInt8*)dst)			= convertSatRte<deInt8>		(src * 127.0f);				break;
365 		case TextureFormat::SNORM_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src * 32767.0f);			break;
366 		case TextureFormat::SNORM_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src * 2147483647.0f);		break;
367 		case TextureFormat::UNORM_INT8:			*((deUint8*)dst)		= convertSatRte<deUint8>	(src * 255.0f);				break;
368 		case TextureFormat::UNORM_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src * 65535.0f);			break;
369 		case TextureFormat::UNORM_INT24:		writeUint24(dst,		  convertSatRteUint24		(src * 16777215.0f));		break;
370 		case TextureFormat::UNORM_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(src * 4294967295.0f);		break;
371 		case TextureFormat::SIGNED_INT8:		*((deInt8*)dst)			= convertSatRte<deInt8>		(src);						break;
372 		case TextureFormat::SIGNED_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src);						break;
373 		case TextureFormat::SIGNED_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src);						break;
374 		case TextureFormat::UNSIGNED_INT8:		*((deUint8*)dst)		= convertSatRte<deUint8>	(src);						break;
375 		case TextureFormat::UNSIGNED_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src);						break;
376 		case TextureFormat::UNSIGNED_INT24:		writeUint24(dst,		  convertSatRteUint24		(src));						break;
377 		case TextureFormat::UNSIGNED_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(src);						break;
378 		case TextureFormat::HALF_FLOAT:			*((deFloat16*)dst)		= deFloat32To16				(src);						break;
379 		case TextureFormat::FLOAT:				*((float*)dst)			= src;													break;
380 		case TextureFormat::FLOAT64:			*((double*)dst)			= (double)src;											break;
381 		case TextureFormat::UNORM_SHORT_10:		*((deUint16*)dst)		= (deUint16)(convertSatRteUint10(src * 1023.0f) << 6u);	break;
382 		case TextureFormat::UNORM_SHORT_12:		*((deUint16*)dst)		= (deUint16)(convertSatRteUint12(src * 4095.0f) << 4u);	break;
383 		case TextureFormat::USCALED_INT8:		*((deUint8*)dst)		= convertSatRte<deUint8>	(src);						break;
384 		case TextureFormat::USCALED_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src);						break;
385 		case TextureFormat::SSCALED_INT8:		*((deInt8*)dst)			= convertSatRte<deInt8>		(src);						break;
386 		case TextureFormat::SSCALED_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src);						break;
387 		default:
388 			DE_ASSERT(DE_FALSE);
389 	}
390 }
391 
392 template <typename T, typename S>
convertSat(S src)393 static inline T convertSat (S src)
394 {
395 	S min = (S)std::numeric_limits<T>::min();
396 	S max = (S)std::numeric_limits<T>::max();
397 
398 	if (src < min)
399 		return (T)min;
400 	else if (src > max)
401 		return (T)max;
402 	else
403 		return (T)src;
404 }
405 
406 template <typename S>
convertSatUint24(S src)407 static inline deUint32 convertSatUint24 (S src)
408 {
409 	S min = (S)0u;
410 	S max = (S)0xFFFFFFu;
411 
412 	if (src < min)
413 		return (deUint32)min;
414 	else if (src > max)
415 		return (deUint32)max;
416 	else
417 		return (deUint32)src;
418 }
419 
420 template <typename S>
convertSatUint10(S src)421 static inline deUint16 convertSatUint10 (S src)
422 {
423 	S min = (S)0u;
424 	S max = (S)0x3FFu;
425 
426 	if (src < min)
427 		return (deUint16)min;
428 	else if (src > max)
429 		return (deUint16)max;
430 	else
431 		return (deUint16)src;
432 }
433 
434 template <typename S>
convertSatUint12(S src)435 static inline deUint16 convertSatUint12 (S src)
436 {
437 	S min = (S)0u;
438 	S max = (S)0xFFFu;
439 
440 	if (src < min)
441 		return (deUint16)min;
442 	else if (src > max)
443 		return (deUint16)max;
444 	else
445 		return (deUint16)src;
446 }
447 
intToChannel(deUint8 * dst,int src,TextureFormat::ChannelType type)448 void intToChannel (deUint8* dst, int src, TextureFormat::ChannelType type)
449 {
450 	// make sure this table is updated if format table is updated
451 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
452 
453 	switch (type)
454 	{
455 		case TextureFormat::SNORM_INT8:			*((deInt8*)dst)			= convertSat<deInt8>	(src);				break;
456 		case TextureFormat::SNORM_INT16:		*((deInt16*)dst)		= convertSat<deInt16>	(src);				break;
457 		case TextureFormat::UNORM_INT8:			*((deUint8*)dst)		= convertSat<deUint8>	(src);				break;
458 		case TextureFormat::UNORM_INT16:		*((deUint16*)dst)		= convertSat<deUint16>	(src);				break;
459 		case TextureFormat::UNORM_INT24:		writeUint24(dst,		  convertSatUint24		(src));				break;
460 		case TextureFormat::SIGNED_INT8:		*((deInt8*)dst)			= convertSat<deInt8>	(src);				break;
461 		case TextureFormat::SIGNED_INT16:		*((deInt16*)dst)		= convertSat<deInt16>	(src);				break;
462 		case TextureFormat::SIGNED_INT32:		*((deInt32*)dst)		= convertSat<deInt32>	(src);				break;
463 		case TextureFormat::SIGNED_INT64:		*((deInt64*)dst)		= convertSat<deInt64>	((deInt64)src);		break;
464 		case TextureFormat::UNSIGNED_INT8:		*((deUint8*)dst)		= convertSat<deUint8>	((deUint32)src);	break;
465 		case TextureFormat::UNSIGNED_INT16:		*((deUint16*)dst)		= convertSat<deUint16>	((deUint32)src);	break;
466 		case TextureFormat::UNSIGNED_INT24:		writeUint24(dst,		  convertSatUint24		((deUint32)src));	break;
467 		case TextureFormat::UNSIGNED_INT32:		*((deUint32*)dst)		= convertSat<deUint32>	((deUint32)src);	break;
468 		case TextureFormat::UNSIGNED_INT64:		*((deUint64*)dst)		= convertSat<deUint64>	((deUint64)src);	break;
469 		case TextureFormat::HALF_FLOAT:			*((deFloat16*)dst)		= deFloat32To16((float)src);				break;
470 		case TextureFormat::FLOAT:				*((float*)dst)			= (float)src;								break;
471 		case TextureFormat::FLOAT64:			*((double*)dst)			= (double)src;								break;
472 		case TextureFormat::UNORM_SHORT_10:		*((deUint16*)dst)		= (deUint16)(convertSatUint10(src) << 6u);	break;
473 		case TextureFormat::UNORM_SHORT_12:		*((deUint16*)dst)		= (deUint16)(convertSatUint12(src) << 4u);	break;
474 		case TextureFormat::USCALED_INT8:		*((deUint8*)dst)		= convertSat<deUint8>	((deUint32)src);	break;
475 		case TextureFormat::USCALED_INT16:		*((deUint16*)dst)		= convertSat<deUint16>	((deUint32)src);	break;
476 		case TextureFormat::SSCALED_INT8:		*((deInt8*)dst)			= convertSat<deInt8>	(src);				break;
477 		case TextureFormat::SSCALED_INT16:		*((deInt16*)dst)		= convertSat<deInt16>	(src);				break;
478 		default:
479 			DE_ASSERT(DE_FALSE);
480 	}
481 }
482 
channelToUnormFloat(deUint32 src,int bits)483 inline float channelToUnormFloat (deUint32 src, int bits)
484 {
485 	const deUint32 maxVal = (1u << bits) - 1;
486 
487 	// \note Will lose precision if bits > 23
488 	return (float)src / (float)maxVal;
489 }
490 
491 //! Extend < 32b signed integer to 32b
signExtend(deUint32 src,int bits)492 inline deInt32 signExtend (deUint32 src, int bits)
493 {
494 	const deUint32 signBit = 1u << (bits-1);
495 
496 	src |= ~((src & signBit) - 1);
497 
498 	return (deInt32)src;
499 }
500 
channelToSnormFloat(deUint32 src,int bits)501 inline float channelToSnormFloat (deUint32 src, int bits)
502 {
503 	const deUint32	range	= (1u << (bits-1)) - 1;
504 
505 	// \note Will lose precision if bits > 24
506 	return de::max(-1.0f, (float)signExtend(src, bits) / (float)range);
507 }
508 
unormFloatToChannel(float src,int bits)509 inline deUint32 unormFloatToChannel (float src, int bits)
510 {
511 	const deUint32	maxVal	= (1u << bits) - 1;
512 	const deUint32	intVal	= convertSatRte<deUint32>(src * (float)maxVal);
513 
514 	return de::min(intVal, maxVal);
515 }
516 
snormFloatToChannel(float src,int bits)517 inline deUint32 snormFloatToChannel (float src, int bits)
518 {
519 	const deInt32	range	= (deInt32)((1u << (bits-1)) - 1u);
520 	const deUint32	mask	= (1u << bits) - 1;
521 	const deInt32	intVal	= convertSatRte<deInt32>(src * (float)range);
522 
523 	return (deUint32)de::clamp(intVal, -range, range) & mask;
524 }
525 
uintToChannel(deUint32 src,int bits)526 inline deUint32 uintToChannel (deUint32 src, int bits)
527 {
528 	const deUint32 maxVal = (1u << bits) - 1;
529 	return de::min(src, maxVal);
530 }
531 
intToChannel(deInt32 src,int bits)532 inline deUint32 intToChannel (deInt32 src, int bits)
533 {
534 	const deInt32	minVal	= -(deInt32)(1u << (bits-1));
535 	const deInt32	maxVal	= (deInt32)((1u << (bits-1)) - 1u);
536 	const deUint32	mask	= (1u << bits) - 1;
537 
538 	return (deUint32)de::clamp(src, minVal, maxVal) & mask;
539 }
540 
unpackRGB999E5(deUint32 color)541 tcu::Vec4 unpackRGB999E5 (deUint32 color)
542 {
543 	const int	mBits	= 9;
544 	const int	eBias	= 15;
545 
546 	deUint32	exp		= color >> 27;
547 	deUint32	bs		= (color >> 18) & ((1<<9)-1);
548 	deUint32	gs		= (color >> 9) & ((1<<9)-1);
549 	deUint32	rs		= color & ((1<<9)-1);
550 
551 	float		e		= deFloatPow(2.0f, (float)((int)exp - eBias - mBits));
552 	float		r		= (float)rs * e;
553 	float		g		= (float)gs * e;
554 	float		b		= (float)bs * e;
555 
556 	return tcu::Vec4(r, g, b, 1.0f);
557 }
558 
isColorOrder(TextureFormat::ChannelOrder order)559 bool isColorOrder (TextureFormat::ChannelOrder order)
560 {
561 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
562 
563 	switch (order)
564 	{
565 		case TextureFormat::R:
566 		case TextureFormat::A:
567 		case TextureFormat::I:
568 		case TextureFormat::L:
569 		case TextureFormat::LA:
570 		case TextureFormat::RG:
571 		case TextureFormat::RA:
572 		case TextureFormat::RGB:
573 		case TextureFormat::RGBA:
574 		case TextureFormat::ARGB:
575 		case TextureFormat::ABGR:
576 		case TextureFormat::BGR:
577 		case TextureFormat::BGRA:
578 		case TextureFormat::sR:
579 		case TextureFormat::sRG:
580 		case TextureFormat::sRGB:
581 		case TextureFormat::sRGBA:
582 		case TextureFormat::sBGR:
583 		case TextureFormat::sBGRA:
584 			return true;
585 
586 		default:
587 			return false;
588 	}
589 }
590 
getImageViewMinLod(ImageViewMinLod & l)591 float getImageViewMinLod(ImageViewMinLod& l)
592 {
593 	return (l.mode == IMAGEVIEWMINLODMODE_PREFERRED) ? l.value : deFloatFloor(l.value);
594 }
595 
596 } // anonymous
597 
isValid(TextureFormat format)598 bool isValid (TextureFormat format)
599 {
600 	const bool	isColor	= isColorOrder(format.order);
601 
602 	switch (format.type)
603 	{
604 		case TextureFormat::SNORM_INT8:
605 		case TextureFormat::SNORM_INT16:
606 		case TextureFormat::SNORM_INT32:
607 			return isColor;
608 
609 		case TextureFormat::UNORM_INT8:
610 		case TextureFormat::UNORM_INT16:
611 		case TextureFormat::UNORM_INT24:
612 		case TextureFormat::UNORM_INT32:
613 			return isColor || format.order == TextureFormat::D;
614 
615 		case TextureFormat::UNORM_BYTE_44:
616 		case TextureFormat::UNSIGNED_BYTE_44:
617 			return format.order == TextureFormat::RG;
618 
619 		case TextureFormat::UNORM_SHORT_565:
620 		case TextureFormat::UNORM_SHORT_555:
621 		case TextureFormat::UNSIGNED_SHORT_565:
622 			return format.order == TextureFormat::RGB || format.order == TextureFormat::BGR;
623 
624 		case TextureFormat::UNORM_SHORT_4444:
625 		case TextureFormat::UNORM_SHORT_5551:
626 		case TextureFormat::UNSIGNED_SHORT_4444:
627 		case TextureFormat::UNSIGNED_SHORT_5551:
628 			return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA
629 				|| format.order == TextureFormat::ARGB || format.order == TextureFormat::ABGR;
630 
631 		case TextureFormat::UNORM_SHORT_1555:
632 			return format.order == TextureFormat::ARGB;
633 
634 		case TextureFormat::UNORM_INT_101010:
635 			return format.order == TextureFormat::RGB;
636 
637 		case TextureFormat::SNORM_INT_1010102_REV:
638 		case TextureFormat::UNORM_INT_1010102_REV:
639 		case TextureFormat::SIGNED_INT_1010102_REV:
640 		case TextureFormat::UNSIGNED_INT_1010102_REV:
641 		case TextureFormat::USCALED_INT_1010102_REV:
642 		case TextureFormat::SSCALED_INT_1010102_REV:
643 			return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
644 
645 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
646 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
647 			return format.order == TextureFormat::RGB;
648 
649 		case TextureFormat::UNSIGNED_INT_16_8_8:
650 			return format.order == TextureFormat::DS;
651 
652 		case TextureFormat::UNSIGNED_INT_24_8:
653 		case TextureFormat::UNSIGNED_INT_24_8_REV:
654 			return format.order == TextureFormat::D || format.order == TextureFormat::DS;
655 
656 		case TextureFormat::SIGNED_INT8:
657 		case TextureFormat::SIGNED_INT16:
658 		case TextureFormat::SIGNED_INT32:
659 		case TextureFormat::SSCALED_INT8:
660 		case TextureFormat::SSCALED_INT16:
661 		case TextureFormat::SIGNED_INT64:
662 			return isColor;
663 
664 		case TextureFormat::UNSIGNED_INT8:
665 		case TextureFormat::UNSIGNED_INT16:
666 		case TextureFormat::UNSIGNED_INT24:
667 		case TextureFormat::UNSIGNED_INT32:
668 		case TextureFormat::USCALED_INT8:
669 		case TextureFormat::USCALED_INT16:
670 		case TextureFormat::UNSIGNED_INT64:
671 			return isColor || format.order == TextureFormat::S;
672 
673 		case TextureFormat::HALF_FLOAT:
674 		case TextureFormat::FLOAT:
675 		case TextureFormat::FLOAT64:
676 			return isColor || format.order == TextureFormat::D;
677 
678 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
679 			return format.order == TextureFormat::DS;
680 
681 		case TextureFormat::UNORM_SHORT_10:
682 		case TextureFormat::UNORM_SHORT_12:
683 			return isColor;
684 
685 		default:
686 			DE_FATAL("Unknown format");
687 			return 0u;
688 	}
689 
690 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
691 }
692 
getNumUsedChannels(TextureFormat::ChannelOrder order)693 int getNumUsedChannels (TextureFormat::ChannelOrder order)
694 {
695 	// make sure this table is updated if type table is updated
696 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
697 
698 	switch (order)
699 	{
700 		case TextureFormat::R:			return 1;
701 		case TextureFormat::A:			return 1;
702 		case TextureFormat::I:			return 1;
703 		case TextureFormat::L:			return 1;
704 		case TextureFormat::LA:			return 2;
705 		case TextureFormat::RG:			return 2;
706 		case TextureFormat::RA:			return 2;
707 		case TextureFormat::RGB:		return 3;
708 		case TextureFormat::RGBA:		return 4;
709 		case TextureFormat::ARGB:		return 4;
710 		case TextureFormat::ABGR:		return 4;
711 		case TextureFormat::BGR:		return 3;
712 		case TextureFormat::BGRA:		return 4;
713 		case TextureFormat::sR:			return 1;
714 		case TextureFormat::sRG:		return 2;
715 		case TextureFormat::sRGB:		return 3;
716 		case TextureFormat::sRGBA:		return 4;
717 		case TextureFormat::sBGR:		return 3;
718 		case TextureFormat::sBGRA:		return 4;
719 		case TextureFormat::D:			return 1;
720 		case TextureFormat::S:			return 1;
721 		case TextureFormat::DS:			return 2;
722 		default:
723 			DE_ASSERT(DE_FALSE);
724 			return 0;
725 	}
726 }
727 
getChannelSize(TextureFormat::ChannelType type)728 int getChannelSize (TextureFormat::ChannelType type)
729 {
730 	// make sure this table is updated if format table is updated
731 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
732 
733 	switch (type)
734 	{
735 		case TextureFormat::SNORM_INT8:			return 1;
736 		case TextureFormat::SNORM_INT16:		return 2;
737 		case TextureFormat::SNORM_INT32:		return 4;
738 		case TextureFormat::UNORM_INT8:			return 1;
739 		case TextureFormat::UNORM_INT16:		return 2;
740 		case TextureFormat::UNORM_INT24:		return 3;
741 		case TextureFormat::UNORM_INT32:		return 4;
742 		case TextureFormat::SIGNED_INT8:		return 1;
743 		case TextureFormat::SIGNED_INT16:		return 2;
744 		case TextureFormat::SIGNED_INT32:		return 4;
745 		case TextureFormat::SIGNED_INT64:		return 8;
746 		case TextureFormat::UNSIGNED_INT8:		return 1;
747 		case TextureFormat::UNSIGNED_INT16:		return 2;
748 		case TextureFormat::UNSIGNED_INT24:		return 3;
749 		case TextureFormat::UNSIGNED_INT32:		return 4;
750 		case TextureFormat::UNSIGNED_INT64:		return 8;
751 		case TextureFormat::HALF_FLOAT:			return 2;
752 		case TextureFormat::FLOAT:				return 4;
753 		case TextureFormat::FLOAT64:			return 8;
754 		case TextureFormat::UNORM_SHORT_10:		return 2;
755 		case TextureFormat::UNORM_SHORT_12:		return 2;
756 		case TextureFormat::USCALED_INT8:		return 1;
757 		case TextureFormat::USCALED_INT16:		return 2;
758 		case TextureFormat::SSCALED_INT8:		return 1;
759 		case TextureFormat::SSCALED_INT16:		return 2;
760 		default:
761 			DE_ASSERT(DE_FALSE);
762 			return 0;
763 	}
764 }
765 
766 /** Get pixel size in bytes. */
getPixelSize(TextureFormat format)767 int getPixelSize (TextureFormat format)
768 {
769 	const TextureFormat::ChannelOrder	order	= format.order;
770 	const TextureFormat::ChannelType	type	= format.type;
771 
772 	DE_ASSERT(isValid(format));
773 
774 	// make sure this table is updated if format table is updated
775 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
776 
777 	switch (type)
778 	{
779 		case TextureFormat::UNORM_BYTE_44:
780 		case TextureFormat::UNSIGNED_BYTE_44:
781 			return 1;
782 
783 		case TextureFormat::UNORM_SHORT_565:
784 		case TextureFormat::UNORM_SHORT_555:
785 		case TextureFormat::UNORM_SHORT_4444:
786 		case TextureFormat::UNORM_SHORT_5551:
787 		case TextureFormat::UNORM_SHORT_1555:
788 		case TextureFormat::UNSIGNED_SHORT_565:
789 		case TextureFormat::UNSIGNED_SHORT_4444:
790 		case TextureFormat::UNSIGNED_SHORT_5551:
791 			return 2;
792 
793 		case TextureFormat::UNORM_INT_101010:
794 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
795 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
796 		case TextureFormat::SNORM_INT_1010102_REV:
797 		case TextureFormat::UNORM_INT_1010102_REV:
798 		case TextureFormat::SIGNED_INT_1010102_REV:
799 		case TextureFormat::UNSIGNED_INT_1010102_REV:
800 		case TextureFormat::UNSIGNED_INT_24_8:
801 		case TextureFormat::UNSIGNED_INT_24_8_REV:
802 		case TextureFormat::UNSIGNED_INT_16_8_8:
803 		case TextureFormat::USCALED_INT_1010102_REV:
804 		case TextureFormat::SSCALED_INT_1010102_REV:
805 			return 4;
806 
807 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
808 			return 8;
809 
810 		default:
811 			return getNumUsedChannels(order) * getChannelSize(type);
812 	}
813 }
814 
getPixelSize(void) const815 int TextureFormat::getPixelSize (void) const
816 {
817 	return ::tcu::getPixelSize(*this);
818 }
819 
getChannelReadSwizzle(TextureFormat::ChannelOrder order)820 const TextureSwizzle& getChannelReadSwizzle (TextureFormat::ChannelOrder order)
821 {
822 	// make sure to update these tables when channel orders are updated
823 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
824 
825 	static const TextureSwizzle INV		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
826 	static const TextureSwizzle R		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
827 	static const TextureSwizzle A		= {{ TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_0	}};
828 	static const TextureSwizzle I		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0	}};
829 	static const TextureSwizzle L		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ONE	}};
830 	static const TextureSwizzle LA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1	}};
831 	static const TextureSwizzle RG		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
832 	static const TextureSwizzle RA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_1	}};
833 	static const TextureSwizzle RGB		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_ONE	}};
834 	static const TextureSwizzle RGBA	= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3	}};
835 	static const TextureSwizzle BGR		= {{ TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ONE	}};
836 	static const TextureSwizzle BGRA	= {{ TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3	}};
837 	static const TextureSwizzle ARGB	= {{ TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_0	}};
838 	static const TextureSwizzle ABGR	= {{ TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_0	}};
839 	static const TextureSwizzle D		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
840 	static const TextureSwizzle S		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_ONE	}};
841 
842 	switch (order)
843 	{
844 		case TextureFormat::R:			return R;
845 		case TextureFormat::A:			return A;
846 		case TextureFormat::I:			return I;
847 		case TextureFormat::L:			return L;
848 		case TextureFormat::LA:			return LA;
849 		case TextureFormat::RG:			return RG;
850 		case TextureFormat::RA:			return RA;
851 		case TextureFormat::RGB:		return RGB;
852 		case TextureFormat::RGBA:		return RGBA;
853 		case TextureFormat::ARGB:		return ARGB;
854 		case TextureFormat::ABGR:		return ABGR;
855 		case TextureFormat::BGR:		return BGR;
856 		case TextureFormat::BGRA:		return BGRA;
857 		case TextureFormat::sR:			return R;
858 		case TextureFormat::sRG:		return RG;
859 		case TextureFormat::sRGB:		return RGB;
860 		case TextureFormat::sRGBA:		return RGBA;
861 		case TextureFormat::sBGR:		return BGR;
862 		case TextureFormat::sBGRA:		return BGRA;
863 		case TextureFormat::D:			return D;
864 		case TextureFormat::S:			return S;
865 
866 		case TextureFormat::DS:
867 			DE_ASSERT(false); // combined formats cannot be read from
868 			return INV;
869 
870 		default:
871 			DE_ASSERT(DE_FALSE);
872 			return INV;
873 	}
874 }
875 
getChannelWriteSwizzle(TextureFormat::ChannelOrder order)876 const TextureSwizzle& getChannelWriteSwizzle (TextureFormat::ChannelOrder order)
877 {
878 	// make sure to update these tables when channel orders are updated
879 	DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
880 
881 	static const TextureSwizzle INV		= {{ TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
882 	static const TextureSwizzle R		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
883 	static const TextureSwizzle A		= {{ TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
884 	static const TextureSwizzle I		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
885 	static const TextureSwizzle L		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
886 	static const TextureSwizzle LA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
887 	static const TextureSwizzle RG		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
888 	static const TextureSwizzle RA		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
889 	static const TextureSwizzle RGB		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_LAST	}};
890 	static const TextureSwizzle RGBA	= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3		}};
891 	static const TextureSwizzle BGR		= {{ TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_LAST	}};
892 	static const TextureSwizzle BGRA	= {{ TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3		}};
893 	static const TextureSwizzle ARGB	= {{ TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2		}};
894 	static const TextureSwizzle ABGR	= {{ TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_0		}};
895 	static const TextureSwizzle D		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
896 	static const TextureSwizzle S		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
897 
898 	switch (order)
899 	{
900 		case TextureFormat::R:			return R;
901 		case TextureFormat::A:			return A;
902 		case TextureFormat::I:			return I;
903 		case TextureFormat::L:			return L;
904 		case TextureFormat::LA:			return LA;
905 		case TextureFormat::RG:			return RG;
906 		case TextureFormat::RA:			return RA;
907 		case TextureFormat::RGB:		return RGB;
908 		case TextureFormat::RGBA:		return RGBA;
909 		case TextureFormat::ARGB:		return ARGB;
910 		case TextureFormat::ABGR:		return ABGR;
911 		case TextureFormat::BGR:		return BGR;
912 		case TextureFormat::BGRA:		return BGRA;
913 		case TextureFormat::sR:			return R;
914 		case TextureFormat::sRG:		return RG;
915 		case TextureFormat::sRGB:		return RGB;
916 		case TextureFormat::sRGBA:		return RGBA;
917 		case TextureFormat::sBGR:		return BGR;
918 		case TextureFormat::sBGRA:		return BGRA;
919 		case TextureFormat::D:			return D;
920 		case TextureFormat::S:			return S;
921 
922 		case TextureFormat::DS:
923 			DE_ASSERT(false); // combined formats cannot be written to
924 			return INV;
925 
926 		default:
927 			DE_ASSERT(DE_FALSE);
928 			return INV;
929 	}
930 }
931 
calculatePackedPitch(const TextureFormat & format,const IVec3 & size)932 IVec3 calculatePackedPitch (const TextureFormat& format, const IVec3& size)
933 {
934 	const int pixelSize		= format.getPixelSize();
935 	const int rowPitch		= pixelSize * size.x();
936 	const int slicePitch	= rowPitch * size.y();
937 
938 	return IVec3(pixelSize, rowPitch, slicePitch);
939 }
940 
ConstPixelBufferAccess(void)941 ConstPixelBufferAccess::ConstPixelBufferAccess (void)
942 	: m_size		(0)
943 	, m_pitch		(0)
944 	, m_divider		(1,1,1)
945 	, m_data		(DE_NULL)
946 {
947 }
948 
ConstPixelBufferAccess(const TextureFormat & format,int width,int height,int depth,const void * data)949 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, const void* data)
950 	: m_format		(format)
951 	, m_size		(width, height, depth)
952 	, m_pitch		(calculatePackedPitch(m_format, m_size))
953 	, m_divider		(1,1,1)
954 	, m_data		((void*)data)
955 {
956 	DE_ASSERT(isValid(format));
957 }
958 
ConstPixelBufferAccess(const TextureFormat & format,const IVec3 & size,const void * data)959 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const void* data)
960 	: m_format		(format)
961 	, m_size		(size)
962 	, m_pitch		(calculatePackedPitch(m_format, m_size))
963 	, m_divider		(1,1,1)
964 	, m_data		((void*)data)
965 {
966 	DE_ASSERT(isValid(format));
967 }
968 
ConstPixelBufferAccess(const TextureFormat & format,int width,int height,int depth,int rowPitch,int slicePitch,const void * data)969 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, const void* data)
970 	: m_format		(format)
971 	, m_size		(width, height, depth)
972 	, m_pitch		(format.getPixelSize(), rowPitch, slicePitch)
973 	, m_divider		(1,1,1)
974 	, m_data		((void*)data)
975 {
976 	DE_ASSERT(isValid(format));
977 }
978 
ConstPixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,const void * data)979 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, const void* data)
980 	: m_format		(format)
981 	, m_size		(size)
982 	, m_pitch		(pitch)
983 	, m_divider		(1,1,1)
984 	, m_data		((void*)data)
985 {
986 	DE_ASSERT(isValid(format));
987 	DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
988 }
989 
ConstPixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,const IVec3 & block,const void * data)990 ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat& format, const IVec3& size, const IVec3& pitch, const IVec3& block, const void* data)
991 	: m_format		(format)
992 	, m_size		(size)
993 	, m_pitch		(pitch)
994 	, m_divider		(block)
995 	, m_data		((void*)data)
996 {
997 	DE_ASSERT(isValid(format));
998 	DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
999 }
1000 
ConstPixelBufferAccess(const TextureLevel & level)1001 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureLevel& level)
1002 	: m_format		(level.getFormat())
1003 	, m_size		(level.getSize())
1004 	, m_pitch		(calculatePackedPitch(m_format, m_size))
1005 	, m_divider		(1,1,1)
1006 	, m_data		((void*)level.getPtr())
1007 {
1008 }
1009 
PixelBufferAccess(const TextureFormat & format,int width,int height,int depth,void * data)1010 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data)
1011 	: ConstPixelBufferAccess(format, width, height, depth, data)
1012 {
1013 }
1014 
PixelBufferAccess(const TextureFormat & format,const IVec3 & size,void * data)1015 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, void* data)
1016 	: ConstPixelBufferAccess(format, size, data)
1017 {
1018 }
1019 
PixelBufferAccess(const TextureFormat & format,int width,int height,int depth,int rowPitch,int slicePitch,void * data)1020 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, void* data)
1021 	: ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, data)
1022 {
1023 }
1024 
PixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,void * data)1025 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, void* data)
1026 	: ConstPixelBufferAccess(format, size, pitch, data)
1027 {
1028 }
1029 
PixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,const IVec3 & block,void * data)1030 PixelBufferAccess::PixelBufferAccess(const TextureFormat& format, const IVec3& size, const IVec3& pitch, const IVec3& block, void* data)
1031 	: ConstPixelBufferAccess(format, size, pitch, block, data)
1032 {
1033 }
1034 
1035 
PixelBufferAccess(TextureLevel & level)1036 PixelBufferAccess::PixelBufferAccess (TextureLevel& level)
1037 	: ConstPixelBufferAccess(level)
1038 {
1039 }
1040 
1041 //! Swizzle generally based on channel order.
1042 template<typename T>
swizzleGe(const Vector<T,4> & v,TextureFormat::ChannelOrder src,TextureFormat::ChannelOrder dst)1043 Vector<T, 4> swizzleGe (const Vector<T, 4>& v, TextureFormat::ChannelOrder src, TextureFormat::ChannelOrder dst)
1044 {
1045 	if (src == dst)
1046 		return v;
1047 	else
1048 	{
1049 		if ((src == TextureFormat::RGBA && dst == TextureFormat::ARGB) ||
1050 			(src == TextureFormat::BGRA && dst == TextureFormat::ABGR))
1051 			return v.swizzle(3, 0, 1, 2);
1052 
1053 		if ((src == TextureFormat::ARGB && dst == TextureFormat::RGBA) ||
1054 			(src == TextureFormat::ABGR && dst == TextureFormat::BGRA))
1055 			return v.swizzle(1, 2, 3, 0);
1056 
1057 		if ((src == TextureFormat::BGRA && dst == TextureFormat::ARGB) ||
1058 		    (src == TextureFormat::ABGR && dst == TextureFormat::RGBA) ||
1059 			(src == TextureFormat::RGBA && dst == TextureFormat::ABGR) ||
1060 			(src == TextureFormat::ARGB && dst == TextureFormat::BGRA))
1061 			return v.swizzle(3, 2, 1, 0);
1062 
1063 		if ((src == TextureFormat::RGB && dst == TextureFormat::BGR) ||
1064 			(src == TextureFormat::BGR && dst == TextureFormat::RGB) ||
1065 			(src == TextureFormat::RGBA && dst == TextureFormat::BGRA) ||
1066 			(src == TextureFormat::BGRA && dst == TextureFormat::RGBA))
1067 			return v.swizzle(2,1,0,3);
1068 
1069 		DE_ASSERT(false);
1070 		return v;
1071 	}
1072 }
1073 
getPixel(int x,int y,int z) const1074 Vec4 ConstPixelBufferAccess::getPixel (int x, int y, int z) const
1075 {
1076 	DE_ASSERT(de::inBounds(x, 0, m_size.x()));
1077 	DE_ASSERT(de::inBounds(y, 0, m_size.y()));
1078 	DE_ASSERT(de::inBounds(z, 0, m_size.z()));
1079 	DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1080 	DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1081 
1082 	const deUint8* pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1083 
1084 	// Optimized fomats.
1085 	if (m_format.type == TextureFormat::UNORM_INT8)
1086 	{
1087 		if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1088 			return readRGBA8888Float(pixelPtr);
1089 		else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1090 			return readRGB888Float(pixelPtr);
1091 	}
1092 
1093 #define UI8(OFFS, COUNT)		((*((const deUint8*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1094 #define UI16(OFFS, COUNT)		((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1095 #define UI32(OFFS, COUNT)		((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1096 #define SI32(OFFS, COUNT)		signExtend(UI32(OFFS, COUNT), (COUNT))
1097 #define UN8(OFFS, COUNT)		channelToUnormFloat(UI8 (OFFS, COUNT), (COUNT))
1098 #define UN16(OFFS, COUNT)		channelToUnormFloat(UI16(OFFS, COUNT), (COUNT))
1099 #define UN32(OFFS, COUNT)		channelToUnormFloat(UI32(OFFS, COUNT), (COUNT))
1100 #define SN32(OFFS, COUNT)		channelToSnormFloat(UI32(OFFS, COUNT), (COUNT))
1101 
1102 	// Packed formats.
1103 	switch (m_format.type)
1104 	{
1105 		case TextureFormat::UNORM_BYTE_44:				return			  Vec4(UN8 (4,   4), UN8 ( 0,  4), 0.0f, 1.0f);
1106 		case TextureFormat::UNSIGNED_BYTE_44:			return			 UVec4(UI8 (4,   4), UI8 ( 0,  4), 0u, 1u).cast<float>();
1107 		case TextureFormat::UNORM_SHORT_565:			return swizzleGe( Vec4(UN16(11,  5), UN16( 5,  6), UN16( 0,  5), 1.0f), m_format.order, TextureFormat::RGB);
1108 		case TextureFormat::UNSIGNED_SHORT_565:			return swizzleGe(UVec4(UI16(11,  5), UI16( 5,  6), UI16( 0,  5), 1u), m_format.order, TextureFormat::RGB).cast<float>();
1109 		case TextureFormat::UNORM_SHORT_555:			return swizzleGe( Vec4(UN16(10,  5), UN16( 5,  5), UN16( 0,  5), 1.0f), m_format.order, TextureFormat::RGB);
1110 		case TextureFormat::UNORM_SHORT_4444:			return swizzleGe( Vec4(UN16(12,  4), UN16( 8,  4), UN16( 4,  4), UN16( 0, 4)), m_format.order, TextureFormat::RGBA);
1111 		case TextureFormat::UNSIGNED_SHORT_4444:		return swizzleGe(UVec4(UI16(12,  4), UI16( 8,  4), UI16( 4,  4), UI16( 0, 4)), m_format.order, TextureFormat::RGBA).cast<float>();
1112 		case TextureFormat::UNORM_SHORT_5551:			return swizzleGe( Vec4(UN16(11,  5), UN16( 6,  5), UN16( 1,  5), UN16( 0, 1)), m_format.order, TextureFormat::RGBA);
1113 		case TextureFormat::UNSIGNED_SHORT_5551:		return swizzleGe(UVec4(UI16(11,  5), UI16( 6,  5), UI16( 1,  5), UI16( 0, 1)), m_format.order, TextureFormat::RGBA).cast<float>();
1114 		case TextureFormat::UNORM_INT_101010:			return			  Vec4(UN32(22, 10), UN32(12, 10), UN32( 2, 10), 1.0f);
1115 		case TextureFormat::UNORM_INT_1010102_REV:		return swizzleGe( Vec4(UN32( 0, 10), UN32(10, 10), UN32(20, 10), UN32(30, 2)), m_format.order, TextureFormat::RGBA);
1116 		case TextureFormat::SNORM_INT_1010102_REV:		return swizzleGe( Vec4(SN32( 0, 10), SN32(10, 10), SN32(20, 10), SN32(30, 2)), m_format.order, TextureFormat::RGBA);
1117 		case TextureFormat::USCALED_INT_1010102_REV:
1118 		case TextureFormat::UNSIGNED_INT_1010102_REV:	return swizzleGe( UVec4(UI32(0, 10), UI32(10, 10), UI32(20, 10), UI32(30, 2)), m_format.order, TextureFormat::RGBA).cast<float>();
1119 		case TextureFormat::SSCALED_INT_1010102_REV:
1120 		case TextureFormat::SIGNED_INT_1010102_REV:		return swizzleGe( UVec4(SI32(0, 10), SI32(10, 10), SI32(20, 10), SI32(30, 2)), m_format.order, TextureFormat::RGBA).cast<float>();
1121 		case TextureFormat::UNSIGNED_INT_999_E5_REV:	return unpackRGB999E5(*((const deUint32*)pixelPtr));
1122 
1123 		case TextureFormat::UNORM_SHORT_1555:
1124 			DE_ASSERT(m_format.order == TextureFormat::ARGB);
1125 			return Vec4(UN16(15, 1), UN16(10, 5), UN16(5, 5), UN16(0, 5)).swizzle(1,2,3,0); // ARGB -> RGBA
1126 
1127 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
1128 			return Vec4(Float11(UI32(0, 11)).asFloat(), Float11(UI32(11, 11)).asFloat(), Float10(UI32(22, 10)).asFloat(), 1.0f);
1129 
1130 		default:
1131 			break;
1132 	}
1133 
1134 #undef UN8
1135 #undef UN16
1136 #undef UN32
1137 #undef SN32
1138 #undef SI32
1139 #undef UI8
1140 #undef UI16
1141 #undef UI32
1142 
1143 	// Generic path.
1144 	Vec4							result;
1145 	const TextureSwizzle::Channel*	channelMap	= getChannelReadSwizzle(m_format.order).components;
1146 	int								channelSize	= getChannelSize(m_format.type);
1147 
1148 	for (int c = 0; c < 4; c++)
1149 	{
1150 		switch (channelMap[c])
1151 		{
1152 			case TextureSwizzle::CHANNEL_0:
1153 			case TextureSwizzle::CHANNEL_1:
1154 			case TextureSwizzle::CHANNEL_2:
1155 			case TextureSwizzle::CHANNEL_3:
1156 				result[c] = channelToFloat(pixelPtr + channelSize*((int)channelMap[c]), m_format.type);
1157 				break;
1158 
1159 			case TextureSwizzle::CHANNEL_ZERO:
1160 				result[c] = 0.0f;
1161 				break;
1162 
1163 			case TextureSwizzle::CHANNEL_ONE:
1164 				result[c] = 1.0f;
1165 				break;
1166 
1167 			default:
1168 				DE_ASSERT(false);
1169 		}
1170 	}
1171 
1172 	return result;
1173 }
1174 
1175 template <typename T>
getPixelIntGeneric(const deUint8 * pixelPtr,const tcu::TextureFormat & format)1176 static tcu::Vector<T, 4> getPixelIntGeneric (const deUint8* pixelPtr, const tcu::TextureFormat& format)
1177 {
1178 	tcu::Vector<T, 4> result;
1179 
1180 	// Generic path.
1181 	const TextureSwizzle::Channel*	channelMap	= getChannelReadSwizzle(format.order).components;
1182 	int								channelSize	= getChannelSize(format.type);
1183 
1184 	for (int c = 0; c < 4; c++)
1185 	{
1186 		switch (channelMap[c])
1187 		{
1188 			case TextureSwizzle::CHANNEL_0:
1189 			case TextureSwizzle::CHANNEL_1:
1190 			case TextureSwizzle::CHANNEL_2:
1191 			case TextureSwizzle::CHANNEL_3:
1192 				result[c] = channelToIntType<T>(pixelPtr + channelSize*((int)channelMap[c]), format.type);
1193 				break;
1194 
1195 			case TextureSwizzle::CHANNEL_ZERO:
1196 				result[c] = 0;
1197 				break;
1198 
1199 			case TextureSwizzle::CHANNEL_ONE:
1200 				result[c] = 1;
1201 				break;
1202 
1203 			default:
1204 				DE_ASSERT(false);
1205 		}
1206 	}
1207 
1208 	return result;
1209 }
1210 
getPixelInt(int x,int y,int z) const1211 IVec4 ConstPixelBufferAccess::getPixelInt (int x, int y, int z) const
1212 {
1213 	DE_ASSERT(de::inBounds(x, 0, m_size.x()));
1214 	DE_ASSERT(de::inBounds(y, 0, m_size.y()));
1215 	DE_ASSERT(de::inBounds(z, 0, m_size.z()));
1216 	DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1217 	DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1218 
1219 	const deUint8* const	pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1220 
1221 	// Optimized fomats.
1222 	if (m_format.type == TextureFormat::UNORM_INT8)
1223 	{
1224 		if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1225 			return readRGBA8888Int(pixelPtr);
1226 		else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1227 			return readRGB888Int(pixelPtr);
1228 	}
1229 
1230 #define U8(OFFS, COUNT)			((*((const deUint8* )pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1231 #define U16(OFFS, COUNT)		((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1232 #define U32(OFFS, COUNT)		((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1233 #define S32(OFFS, COUNT)		signExtend(U32(OFFS, COUNT), (COUNT))
1234 
1235 	switch (m_format.type)
1236 	{
1237 		case TextureFormat::UNSIGNED_BYTE_44:			// Fall-through
1238 		case TextureFormat::UNORM_BYTE_44:				return			 UVec4(U8 ( 4,  4), U8 ( 0,  4), 0u, 1u).cast<int>();
1239 		case TextureFormat::UNSIGNED_SHORT_565:			// Fall-through
1240 		case TextureFormat::UNORM_SHORT_565:			return swizzleGe(UVec4(U16(11,  5), U16( 5,  6), U16( 0,  5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
1241 		case TextureFormat::UNORM_SHORT_555:			return swizzleGe(UVec4(U16(10,  5), U16( 5,  5), U16( 0,  5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
1242 		case TextureFormat::UNSIGNED_SHORT_4444:		// Fall-through
1243 		case TextureFormat::UNORM_SHORT_4444:			return swizzleGe(UVec4(U16(12,  4), U16( 8,  4), U16( 4,  4), U16( 0, 4)).cast<int>(), m_format.order, TextureFormat::RGBA);
1244 		case TextureFormat::UNSIGNED_SHORT_5551:		// Fall-through
1245 		case TextureFormat::UNORM_SHORT_5551:			return swizzleGe(UVec4(U16(11,  5), U16( 6,  5), U16( 1,  5), U16( 0, 1)).cast<int>(), m_format.order, TextureFormat::RGBA);
1246 		case TextureFormat::UNORM_INT_101010:			return			 UVec4(U32(22, 10), U32(12, 10), U32( 2, 10), 1).cast<int>();
1247 		case TextureFormat::UNORM_INT_1010102_REV:		// Fall-through
1248 		case TextureFormat::USCALED_INT_1010102_REV:	// Fall-through
1249 		case TextureFormat::UNSIGNED_INT_1010102_REV:	return swizzleGe(UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)), m_format.order, TextureFormat::RGBA).cast<int>();
1250 		case TextureFormat::SNORM_INT_1010102_REV:		// Fall-through
1251 		case TextureFormat::SSCALED_INT_1010102_REV:	// Fall-through
1252 		case TextureFormat::SIGNED_INT_1010102_REV:		return swizzleGe(IVec4(S32( 0, 10), S32(10, 10), S32(20, 10), S32(30, 2)), m_format.order, TextureFormat::RGBA);
1253 
1254 		case TextureFormat::UNORM_SHORT_1555:
1255 			DE_ASSERT(m_format.order == TextureFormat::ARGB);
1256 			return UVec4(U16(15, 1), U16(10, 5), U16(5, 5), U16(0, 5)).cast<int>().swizzle(1,2,3,0); // ARGB -> RGBA
1257 
1258 		default:
1259 			break; // To generic path.
1260 	}
1261 
1262 #undef U8
1263 #undef U16
1264 #undef U32
1265 #undef S32
1266 
1267 	// Generic path.
1268 	return getPixelIntGeneric<int>(pixelPtr, m_format);
1269 }
1270 
getPixelInt64(int x,int y,int z) const1271 I64Vec4 ConstPixelBufferAccess::getPixelInt64 (int x, int y, int z) const
1272 {
1273 	// Rely on getPixelInt() for some formats.
1274 	if (m_format.type == TextureFormat::UNORM_INT8 &&
1275 		(m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA ||
1276 		 m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB))
1277 	{
1278 			return getPixelInt(x, y, z).cast<deInt64>();
1279 	}
1280 
1281 	switch (m_format.type)
1282 	{
1283 		case TextureFormat::UNSIGNED_BYTE_44:
1284 		case TextureFormat::UNORM_BYTE_44:
1285 		case TextureFormat::UNSIGNED_SHORT_565:
1286 		case TextureFormat::UNORM_SHORT_565:
1287 		case TextureFormat::UNORM_SHORT_555:
1288 		case TextureFormat::UNSIGNED_SHORT_4444:
1289 		case TextureFormat::UNORM_SHORT_4444:
1290 		case TextureFormat::UNSIGNED_SHORT_5551:
1291 		case TextureFormat::UNORM_SHORT_5551:
1292 		case TextureFormat::UNORM_INT_101010:
1293 		case TextureFormat::UNORM_INT_1010102_REV:
1294 		case TextureFormat::USCALED_INT_1010102_REV:
1295 		case TextureFormat::UNSIGNED_INT_1010102_REV:
1296 		case TextureFormat::SNORM_INT_1010102_REV:
1297 		case TextureFormat::SSCALED_INT_1010102_REV:
1298 		case TextureFormat::SIGNED_INT_1010102_REV:
1299 		case TextureFormat::UNORM_SHORT_1555:
1300 			return getPixelInt(x, y, z).cast<deInt64>();
1301 
1302 		default:
1303 			break; // To generic path.
1304 	}
1305 
1306 	// Generic path.
1307 	auto pixelPtr = reinterpret_cast<const deUint8*>(getPixelPtr(x, y, z));
1308 	return getPixelIntGeneric<deInt64>(pixelPtr, m_format);
1309 }
1310 
1311 template<>
getPixelT(int x,int y,int z) const1312 Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1313 {
1314 	return getPixel(x, y, z);
1315 }
1316 
1317 template<>
getPixelT(int x,int y,int z) const1318 IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1319 {
1320 	return getPixelInt(x, y, z);
1321 }
1322 
1323 template<>
getPixelT(int x,int y,int z) const1324 UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1325 {
1326 	return getPixelUint(x, y, z);
1327 }
1328 
1329 template<>
getPixelT(int x,int y,int z) const1330 I64Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1331 {
1332 	return getPixelInt64(x, y, z);
1333 }
1334 
1335 template<>
getPixelT(int x,int y,int z) const1336 U64Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1337 {
1338 	return getPixelUint64(x, y, z);
1339 }
1340 
getPixDepth(int x,int y,int z) const1341 float ConstPixelBufferAccess::getPixDepth (int x, int y, int z) const
1342 {
1343 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
1344 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
1345 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
1346 
1347 	const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1348 
1349 	switch (m_format.type)
1350 	{
1351 		case TextureFormat::UNSIGNED_INT_16_8_8:
1352 			DE_ASSERT(m_format.order == TextureFormat::DS);
1353 			return (float)readUint32High16(pixelPtr) / 65535.0f;
1354 
1355 		case TextureFormat::UNSIGNED_INT_24_8:
1356 			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1357 			return (float)readUint32High24(pixelPtr) / 16777215.0f;
1358 
1359 		case TextureFormat::UNSIGNED_INT_24_8_REV:
1360 			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1361 			return (float)readUint32Low24(pixelPtr) / 16777215.0f;
1362 
1363 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1364 			DE_ASSERT(m_format.order == TextureFormat::DS);
1365 			return *((const float*)pixelPtr);
1366 
1367 		default:
1368 			DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1369 			return channelToFloat(pixelPtr, m_format.type);
1370 	}
1371 }
1372 
getPixStencil(int x,int y,int z) const1373 int ConstPixelBufferAccess::getPixStencil (int x, int y, int z) const
1374 {
1375 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
1376 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
1377 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
1378 
1379 	const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1380 
1381 	switch (m_format.type)
1382 	{
1383 		case TextureFormat::UNSIGNED_INT_24_8_REV:
1384 			DE_ASSERT(m_format.order == TextureFormat::DS);
1385 			return (int)readUint32High8(pixelPtr);
1386 
1387 		case TextureFormat::UNSIGNED_INT_16_8_8:
1388 		case TextureFormat::UNSIGNED_INT_24_8:
1389 			DE_ASSERT(m_format.order == TextureFormat::DS);
1390 			return (int)readUint32Low8(pixelPtr);
1391 
1392 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1393 			DE_ASSERT(m_format.order == TextureFormat::DS);
1394 			return (int)readUint32Low8(pixelPtr + 4);
1395 
1396 		default:
1397 		{
1398 			DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1399 			return channelToInt(pixelPtr, m_format.type);
1400 		}
1401 	}
1402 }
1403 
setPixel(const Vec4 & color,int x,int y,int z) const1404 void PixelBufferAccess::setPixel (const Vec4& color, int x, int y, int z) const
1405 {
1406 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
1407 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
1408 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
1409 	DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1410 	DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1411 
1412 	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1413 
1414 	// Optimized fomats.
1415 	if (m_format.type == TextureFormat::UNORM_INT8)
1416 	{
1417 		if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1418 		{
1419 			writeRGBA8888Float(pixelPtr, color);
1420 			return;
1421 		}
1422 		else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1423 		{
1424 			writeRGB888Float(pixelPtr, color);
1425 			return;
1426 		}
1427 	}
1428 
1429 #define PN(VAL, OFFS, BITS)		(unormFloatToChannel((VAL), (BITS)) << (OFFS))
1430 #define PS(VAL, OFFS, BITS)		(snormFloatToChannel((VAL), (BITS)) << (OFFS))
1431 #define PU(VAL, OFFS, BITS)		(uintToChannel((VAL), (BITS)) << (OFFS))
1432 #define PI(VAL, OFFS, BITS)		(intToChannel((VAL), (BITS)) << (OFFS))
1433 
1434 	switch (m_format.type)
1435 	{
1436 		case TextureFormat::UNORM_BYTE_44:		*((deUint8 *)pixelPtr) = (deUint8)(PN(color[0], 4, 4) | PN(color[1], 0, 4));						break;
1437 		case TextureFormat::UNSIGNED_BYTE_44:	*((deUint8 *)pixelPtr) = (deUint8)(PU((deUint32)color[0], 4, 4) | PU((deUint32)color[1], 0, 4));	break;
1438 		case TextureFormat::UNORM_INT_101010:	*((deUint32*)pixelPtr) = PN(color[0], 22, 10) | PN(color[1], 12, 10) | PN(color[2], 2, 10);			break;
1439 
1440 		case TextureFormat::UNORM_SHORT_565:
1441 		{
1442 			const Vec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1443 			*((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 5, 6) | PN(swizzled[2], 0, 5));
1444 			break;
1445 		}
1446 
1447 		case TextureFormat::UNSIGNED_SHORT_565:
1448 		{
1449 			const UVec4 swizzled = swizzleGe(color.cast<deUint32>(), TextureFormat::RGB, m_format.order);
1450 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
1451 			break;
1452 		}
1453 
1454 		case TextureFormat::UNORM_SHORT_555:
1455 		{
1456 			const Vec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1457 			*((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 10, 5) | PN(swizzled[1], 5, 5) | PN(swizzled[2], 0, 5));
1458 			break;
1459 		}
1460 
1461 		case TextureFormat::UNORM_SHORT_4444:
1462 		{
1463 			const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1464 			*((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 12, 4) | PN(swizzled[1], 8, 4) | PN(swizzled[2], 4, 4) | PN(swizzled[3], 0, 4));
1465 			break;
1466 		}
1467 
1468 		case TextureFormat::UNSIGNED_SHORT_4444:
1469 		{
1470 			const UVec4 swizzled = swizzleGe(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1471 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
1472 			break;
1473 		}
1474 
1475 		case TextureFormat::UNORM_SHORT_5551:
1476 		{
1477 			const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1478 			*((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 6, 5) | PN(swizzled[2], 1, 5) | PN(swizzled[3], 0, 1));
1479 			break;
1480 		}
1481 
1482 		case TextureFormat::UNORM_SHORT_1555:
1483 		{
1484 			const Vec4 swizzled = color.swizzle(3,0,1,2); // RGBA -> ARGB
1485 			*((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 15, 1) | PN(swizzled[1], 10, 5) | PN(swizzled[2], 5, 5) | PN(swizzled[3], 0, 5));
1486 			break;
1487 		}
1488 
1489 		case TextureFormat::UNSIGNED_SHORT_5551:
1490 		{
1491 			const UVec4 swizzled = swizzleGe(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1492 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
1493 			break;
1494 		}
1495 
1496 		case TextureFormat::UNORM_INT_1010102_REV:
1497 		{
1498 			const Vec4 u = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1499 			*((deUint32*)pixelPtr) = PN(u[0], 0, 10) | PN(u[1], 10, 10) | PN(u[2], 20, 10) | PN(u[3], 30, 2);
1500 			break;
1501 		}
1502 
1503 		case TextureFormat::SNORM_INT_1010102_REV:
1504 		{
1505 			const Vec4 u = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1506 			*((deUint32*)pixelPtr) = PS(u[0], 0, 10) | PS(u[1], 10, 10) | PS(u[2], 20, 10) | PS(u[3], 30, 2);
1507 			break;
1508 		}
1509 
1510 		case TextureFormat::UNSIGNED_INT_1010102_REV:
1511 		case TextureFormat::USCALED_INT_1010102_REV:
1512 		{
1513 			const UVec4 u = swizzleGe(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1514 			*((deUint32*)pixelPtr) = PU(u[0], 0, 10) | PU(u[1], 10, 10) | PU(u[2], 20, 10) | PU(u[3], 30, 2);
1515 			break;
1516 		}
1517 
1518 		case TextureFormat::SIGNED_INT_1010102_REV:
1519 		case TextureFormat::SSCALED_INT_1010102_REV:
1520 		{
1521 			const IVec4 u = swizzleGe(color.cast<deInt32>(), TextureFormat::RGBA, m_format.order);
1522 			*((deUint32*)pixelPtr) = PI(u[0], 0, 10) | PI(u[1], 10, 10) | PI(u[2], 20, 10) | PI(u[3], 30, 2);
1523 			break;
1524 		}
1525 
1526 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
1527 			*((deUint32*)pixelPtr) = Float11(color[0]).bits() | (Float11(color[1]).bits() << 11) | (Float10(color[2]).bits() << 22);
1528 			break;
1529 
1530 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
1531 			*((deUint32*)pixelPtr) = packRGB999E5(color);
1532 			break;
1533 
1534 		default:
1535 		{
1536 			// Generic path.
1537 			int								numChannels	= getNumUsedChannels(m_format.order);
1538 			const TextureSwizzle::Channel*	map			= getChannelWriteSwizzle(m_format.order).components;
1539 			int								channelSize	= getChannelSize(m_format.type);
1540 
1541 			for (int c = 0; c < numChannels; c++)
1542 			{
1543 				DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1544 				floatToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1545 			}
1546 			break;
1547 		}
1548 	}
1549 
1550 #undef PN
1551 #undef PS
1552 #undef PU
1553 #undef PI
1554 }
1555 
setPixel(const IVec4 & color,int x,int y,int z) const1556 void PixelBufferAccess::setPixel (const IVec4& color, int x, int y, int z) const
1557 {
1558 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
1559 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
1560 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
1561 	DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1562 	DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1563 
1564 	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1565 
1566 	// Optimized fomats.
1567 	if (m_format.type == TextureFormat::UNORM_INT8)
1568 	{
1569 		if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1570 		{
1571 			writeRGBA8888Int(pixelPtr, color);
1572 			return;
1573 		}
1574 		else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1575 		{
1576 			writeRGB888Int(pixelPtr, color);
1577 			return;
1578 		}
1579 	}
1580 
1581 #define PU(VAL, OFFS, BITS)		(uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1582 #define PI(VAL, OFFS, BITS)		(intToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1583 
1584 	switch (m_format.type)
1585 	{
1586 		case TextureFormat::UNSIGNED_BYTE_44:	// Fall-through
1587 		case TextureFormat::UNORM_BYTE_44:		*((deUint8 *)pixelPtr) = (deUint8 )(PU(color[0],  4, 4) | PU(color[1], 0, 4));				break;
1588 		case TextureFormat::UNORM_INT_101010:	*((deUint32*)pixelPtr) = PU(color[0], 22, 10) | PU(color[1], 12, 10) | PU(color[2], 2, 10);	break;
1589 
1590 		case TextureFormat::UNORM_SHORT_565:
1591 		case TextureFormat::UNSIGNED_SHORT_565:
1592 		{
1593 			const IVec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1594 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
1595 			break;
1596 		}
1597 
1598 		case TextureFormat::UNORM_SHORT_555:
1599 		{
1600 			const IVec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1601 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 10, 5) | PU(swizzled[1], 5, 5) | PU(swizzled[2], 0, 5));
1602 			break;
1603 		}
1604 
1605 		case TextureFormat::UNORM_SHORT_4444:
1606 		case TextureFormat::UNSIGNED_SHORT_4444:
1607 		{
1608 			const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1609 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
1610 			break;
1611 		}
1612 
1613 		case TextureFormat::UNORM_SHORT_5551:
1614 		case TextureFormat::UNSIGNED_SHORT_5551:
1615 		{
1616 			const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1617 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
1618 			break;
1619 		}
1620 
1621 		case TextureFormat::UNORM_SHORT_1555:
1622 		{
1623 			const IVec4 swizzled = color.swizzle(3,0,1,2); // RGBA -> ARGB
1624 			*((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 15, 1) | PU(swizzled[1], 10, 5) | PU(swizzled[2], 5, 5) | PU(swizzled[3], 0, 5));
1625 			break;
1626 		}
1627 
1628 		case TextureFormat::UNORM_INT_1010102_REV:
1629 		case TextureFormat::UNSIGNED_INT_1010102_REV:
1630 		case TextureFormat::USCALED_INT_1010102_REV:
1631 		{
1632 			const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1633 			*((deUint32*)pixelPtr) = PU(swizzled[0],  0, 10) | PU(swizzled[1], 10, 10) | PU(swizzled[2], 20, 10) | PU(swizzled[3], 30, 2);
1634 			break;
1635 		}
1636 
1637 		case TextureFormat::SNORM_INT_1010102_REV:
1638 		case TextureFormat::SIGNED_INT_1010102_REV:
1639 		case TextureFormat::SSCALED_INT_1010102_REV:
1640 		{
1641 			const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1642 			*((deUint32*)pixelPtr) = PI(swizzled[0],  0, 10) | PI(swizzled[1], 10, 10) | PI(swizzled[2], 20, 10) | PI(swizzled[3], 30, 2);
1643 			break;
1644 		}
1645 
1646 		default:
1647 		{
1648 			// Generic path.
1649 			int								numChannels	= getNumUsedChannels(m_format.order);
1650 			const TextureSwizzle::Channel*	map			= getChannelWriteSwizzle(m_format.order).components;
1651 			int								channelSize	= getChannelSize(m_format.type);
1652 
1653 			for (int c = 0; c < numChannels; c++)
1654 			{
1655 				DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1656 				intToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1657 			}
1658 			break;
1659 		}
1660 	}
1661 
1662 #undef PU
1663 #undef PI
1664 }
1665 
setPixDepth(float depth,int x,int y,int z) const1666 void PixelBufferAccess::setPixDepth (float depth, int x, int y, int z) const
1667 {
1668 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
1669 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
1670 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
1671 
1672 	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1673 
1674 	switch (m_format.type)
1675 	{
1676 		case TextureFormat::UNSIGNED_INT_16_8_8:
1677 			DE_ASSERT(m_format.order == TextureFormat::DS);
1678 			writeUint32High16(pixelPtr, convertSatRte<deUint16>(depth * 65535.0f));
1679 			break;
1680 
1681 		case TextureFormat::UNSIGNED_INT_24_8:
1682 			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1683 			writeUint32High24(pixelPtr,  convertSatRteUint24(depth * 16777215.0f));
1684 			break;
1685 
1686 		case TextureFormat::UNSIGNED_INT_24_8_REV:
1687 			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1688 			writeUint32Low24(pixelPtr,  convertSatRteUint24(depth * 16777215.0f));
1689 			break;
1690 
1691 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1692 			DE_ASSERT(m_format.order == TextureFormat::DS);
1693 			*((float*)pixelPtr) = depth;
1694 			break;
1695 
1696 		default:
1697 			DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1698 			floatToChannel(pixelPtr, depth, m_format.type);
1699 			break;
1700 	}
1701 }
1702 
setPixStencil(int stencil,int x,int y,int z) const1703 void PixelBufferAccess::setPixStencil (int stencil, int x, int y, int z) const
1704 {
1705 	DE_ASSERT(de::inBounds(x, 0, getWidth()));
1706 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
1707 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
1708 
1709 	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1710 
1711 	switch (m_format.type)
1712 	{
1713 		case TextureFormat::UNSIGNED_INT_16_8_8:
1714 		case TextureFormat::UNSIGNED_INT_24_8:
1715 			DE_ASSERT(m_format.order == TextureFormat::DS);
1716 			writeUint32Low8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
1717 			break;
1718 
1719 		case TextureFormat::UNSIGNED_INT_24_8_REV:
1720 			DE_ASSERT(m_format.order == TextureFormat::DS);
1721 			writeUint32High8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
1722 			break;
1723 
1724 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1725 			DE_ASSERT(m_format.order == TextureFormat::DS);
1726 			writeUint32Low8(pixelPtr + 4, convertSat<deUint8>((deUint32)stencil));
1727 			break;
1728 
1729 		default:
1730 			DE_ASSERT(m_format.order == TextureFormat::S);  // no other combined depth stencil types
1731 			intToChannel(pixelPtr, stencil, m_format.type);
1732 			break;
1733 	}
1734 }
1735 
imod(int a,int b)1736 static inline int imod (int a, int b)
1737 {
1738 	int m = a % b;
1739 	return m < 0 ? m + b : m;
1740 }
1741 
mirror(int a)1742 static inline int mirror (int a)
1743 {
1744 	return a >= 0 ? a : -(1 + a);
1745 }
1746 
1747 // Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
rint(float a)1748 static inline float rint (float a)
1749 {
1750 	DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
1751 
1752 	float		fracVal		= deFloatFrac(a);
1753 
1754 	if (fracVal != 0.5f)
1755 		return deFloatRound(a); // Ordinary case.
1756 
1757 	float	floorVal	= a - fracVal;
1758 	bool	roundUp		= (deInt64)floorVal % 2 != 0;
1759 
1760 	return floorVal + (roundUp ? 1.0f : 0.0f);
1761 }
1762 
wrap(Sampler::WrapMode mode,int c,int size)1763 static inline int wrap (Sampler::WrapMode mode, int c, int size)
1764 {
1765 	switch (mode)
1766 	{
1767 		case tcu::Sampler::CLAMP_TO_BORDER:
1768 			return deClamp32(c, -1, size);
1769 
1770 		case tcu::Sampler::CLAMP_TO_EDGE:
1771 			return deClamp32(c, 0, size-1);
1772 
1773 		case tcu::Sampler::REPEAT_GL:
1774 			return imod(c, size);
1775 
1776 		case tcu::Sampler::REPEAT_CL:
1777 			return imod(c, size);
1778 
1779 		case tcu::Sampler::MIRRORED_ONCE:
1780 			c = deClamp32(c, -size, size);
1781 			// Fall-through
1782 
1783 		case tcu::Sampler::MIRRORED_REPEAT_GL:
1784 			return (size - 1) - mirror(imod(c, 2*size) - size);
1785 
1786 		case tcu::Sampler::MIRRORED_REPEAT_CL:
1787 			return deClamp32(c, 0, size-1); // \note Actual mirroring done already in unnormalization function.
1788 
1789 		default:
1790 			DE_ASSERT(DE_FALSE);
1791 			return 0;
1792 	}
1793 }
1794 
1795 // Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL wrap modes; otherwise ordinary unnormalization.
unnormalize(Sampler::WrapMode mode,float c,int size)1796 static inline float unnormalize (Sampler::WrapMode mode, float c, int size)
1797 {
1798 	switch (mode)
1799 	{
1800 		case tcu::Sampler::CLAMP_TO_EDGE:
1801 		case tcu::Sampler::CLAMP_TO_BORDER:
1802 		case tcu::Sampler::REPEAT_GL:
1803 		case tcu::Sampler::MIRRORED_REPEAT_GL:
1804 		case tcu::Sampler::MIRRORED_ONCE:		// Fall-through (ordinary case).
1805 			return (float)size*c;
1806 
1807 		case tcu::Sampler::REPEAT_CL:
1808 			return (float)size * (c - deFloatFloor(c));
1809 
1810 		case tcu::Sampler::MIRRORED_REPEAT_CL:
1811 			return (float)size * deFloatAbs(c - 2.0f * rint(0.5f * c));
1812 
1813 		default:
1814 			DE_ASSERT(DE_FALSE);
1815 			return 0.0f;
1816 	}
1817 }
1818 
isFixedPointDepthTextureFormat(const tcu::TextureFormat & format)1819 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
1820 {
1821 	DE_ASSERT(format.order == TextureFormat::D || format.order == TextureFormat::R);
1822 
1823 	const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
1824 	if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
1825 		return false;
1826 	else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1827 		return true;
1828 	else
1829 	{
1830 		DE_ASSERT(false);
1831 		return false;
1832 	}
1833 }
1834 
1835 // Texel lookup with color conversion.
lookup(const ConstPixelBufferAccess & access,int i,int j,int k)1836 static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, int k)
1837 {
1838 	const TextureFormat&	format	= access.getFormat();
1839 
1840 	if (isSRGB(format))
1841 	{
1842 		if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGB)
1843 				return sRGB8ToLinear(access.getPixelUint(i, j, k));
1844 		else if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGBA)
1845 				return sRGBA8ToLinear(access.getPixelUint(i, j, k));
1846 		else
1847 			return sRGBToLinear(access.getPixel(i, j, k));
1848 	}
1849 	else
1850 	{
1851 		return access.getPixel(i, j, k);
1852 	}
1853 }
1854 
1855 // Border texel lookup with color conversion.
lookupBorder(const tcu::TextureFormat & format,const tcu::Sampler & sampler)1856 static inline Vec4 lookupBorder (const tcu::TextureFormat& format, const tcu::Sampler& sampler)
1857 {
1858 	// "lookup" for a combined format does not make sense, disallow
1859 	DE_ASSERT(!isCombinedDepthStencilType(format.type));
1860 
1861 	const tcu::TextureChannelClass	channelClass			= tcu::getTextureChannelClass(format.type);
1862 	const bool						isFloat					= channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1863 	const bool						isFixed					= channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1864 															  channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1865 	const bool						isPureInteger			= channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
1866 	const bool						isPureUnsignedInteger	= channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1867 
1868 	if (isFloat || isFixed)
1869 		return sampleTextureBorder<float>(format, sampler);
1870 	else if (isPureInteger)
1871 		return sampleTextureBorder<deInt32>(format, sampler).cast<float>();
1872 	else if (isPureUnsignedInteger)
1873 		return sampleTextureBorder<deUint32>(format, sampler).cast<float>();
1874 	else
1875 	{
1876 		DE_ASSERT(false);
1877 		return Vec4(-1.0);
1878 	}
1879 }
1880 
execCompare(const tcu::Vec4 & color,Sampler::CompareMode compare,int chanNdx,float ref_,bool isFixedPoint)1881 static inline float execCompare (const tcu::Vec4& color, Sampler::CompareMode compare, int chanNdx, float ref_, bool isFixedPoint)
1882 {
1883 	const bool	clampValues	= isFixedPoint;	// if comparing against a floating point texture, ref (and value) is not clamped
1884 	const float	cmp			= (clampValues) ? (de::clamp(color[chanNdx], 0.0f, 1.0f)) : (color[chanNdx]);
1885 	const float	ref			= (clampValues) ? (de::clamp(ref_, 0.0f, 1.0f)) : (ref_);
1886 	bool		res			= false;
1887 
1888 	switch (compare)
1889 	{
1890 		case Sampler::COMPAREMODE_LESS:				res = ref < cmp;	break;
1891 		case Sampler::COMPAREMODE_LESS_OR_EQUAL:	res = ref <= cmp;	break;
1892 		case Sampler::COMPAREMODE_GREATER:			res = ref > cmp;	break;
1893 		case Sampler::COMPAREMODE_GREATER_OR_EQUAL:	res = ref >= cmp;	break;
1894 		case Sampler::COMPAREMODE_EQUAL:			res = ref == cmp;	break;
1895 		case Sampler::COMPAREMODE_NOT_EQUAL:		res = ref != cmp;	break;
1896 		case Sampler::COMPAREMODE_ALWAYS:			res = true;			break;
1897 		case Sampler::COMPAREMODE_NEVER:			res = false;		break;
1898 		default:
1899 			DE_ASSERT(false);
1900 	}
1901 
1902 	return res ? 1.0f : 0.0f;
1903 }
1904 
sampleNearest1D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,const IVec2 & offset)1905 static Vec4 sampleNearest1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1906 {
1907 	int width	= access.getWidth();
1908 
1909 	int x = deFloorFloatToInt32(u)+offset.x();
1910 
1911 	// Check for CLAMP_TO_BORDER.
1912 	if (sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))
1913 		return lookupBorder(access.getFormat(), sampler);
1914 
1915 	int i = wrap(sampler.wrapS, x, width);
1916 
1917 	return lookup(access, i, offset.y(), 0);
1918 }
1919 
sampleNearest2D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,const IVec3 & offset)1920 static Vec4 sampleNearest2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1921 {
1922 	int width	= access.getWidth();
1923 	int height	= access.getHeight();
1924 
1925 	int x = deFloorFloatToInt32(u)+offset.x();
1926 	int y = deFloorFloatToInt32(v)+offset.y();
1927 
1928 	// Check for CLAMP_TO_BORDER.
1929 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
1930 		(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)))
1931 		return lookupBorder(access.getFormat(), sampler);
1932 
1933 	int i = wrap(sampler.wrapS, x, width);
1934 	int j = wrap(sampler.wrapT, y, height);
1935 
1936 	return lookup(access, i, j, offset.z());
1937 }
1938 
sampleNearest3D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,float w,const IVec3 & offset)1939 static Vec4 sampleNearest3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
1940 {
1941 	int width	= access.getWidth();
1942 	int height	= access.getHeight();
1943 	int depth	= access.getDepth();
1944 
1945 	int x = deFloorFloatToInt32(u)+offset.x();
1946 	int y = deFloorFloatToInt32(v)+offset.y();
1947 	int z = deFloorFloatToInt32(w)+offset.z();
1948 
1949 	// Check for CLAMP_TO_BORDER.
1950 	if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))	||
1951 		(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height))	||
1952 		(sampler.wrapR == Sampler::CLAMP_TO_BORDER && !deInBounds32(z, 0, depth)))
1953 		return lookupBorder(access.getFormat(), sampler);
1954 
1955 	int i = wrap(sampler.wrapS, x, width);
1956 	int j = wrap(sampler.wrapT, y, height);
1957 	int k = wrap(sampler.wrapR, z, depth);
1958 
1959 	return lookup(access, i, j, k);
1960 }
1961 
sampleLinear1D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,const IVec2 & offset)1962 static Vec4 sampleLinear1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1963 {
1964 	int w = access.getWidth();
1965 
1966 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1967 	int x1 = x0+1;
1968 
1969 	int i0 = wrap(sampler.wrapS, x0, w);
1970 	int i1 = wrap(sampler.wrapS, x1, w);
1971 
1972 	float a = deFloatFrac(u-0.5f);
1973 
1974 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1975 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1976 
1977 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1978 	Vec4 p0 = i0UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, offset.y(), 0);
1979 	Vec4 p1 = i1UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, offset.y(), 0);
1980 
1981 	// Interpolate.
1982 	return p0 * (1.0f - a) + p1 * a;
1983 }
1984 
sampleCubic1D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,const IVec2 & offset)1985 static Vec4 sampleCubic1D(const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1986 {
1987 	int width = access.getWidth();
1988 
1989 	tcu::IVec4 x, i;
1990 
1991 	x[0] = deFloorFloatToInt32(u - 1.5f) + offset.x();
1992 	x[1] = x[0] + 1;
1993 	x[2] = x[1] + 1;
1994 	x[3] = x[2] + 1;
1995 
1996 	for (deUint32 m = 0; m < 4; ++m)
1997 		i[m] = wrap(sampler.wrapS, x[m], width);
1998 
1999 	bool iUseBorder[4];
2000 	for (deUint32 m = 0; m < 4; ++m)
2001 		iUseBorder[m] = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i[m], 0, width);
2002 
2003 	// Catmull-Rom basis matrix
2004 	static const float crValues[16] = { 0.0f,	1.0f,	0.0f,	0.0f,
2005 										-0.5f,	0.0f,	0.5f,	0.0f,
2006 										1.0f,	-2.5f,	2.0f,	-0.5f,
2007 										-0.5f,	1.5f,	-1.5f,	0.5f };
2008 	static const tcu::Mat4 crBasis(crValues);
2009 
2010 	float		a = deFloatFrac(u - 0.5f);
2011 	tcu::Vec4	alpha(1, a, a*a, a*a*a);
2012 	tcu::Vec4	wi = alpha * crBasis;
2013 
2014 	tcu::Vec4 result(0.0f, 0.0f, 0.0f, 0.0f);
2015 	for (deUint32 m = 0; m < 4; ++m)
2016 	{
2017 		tcu::Vec4 p = (iUseBorder[m]) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i[m], offset.y(), 0);
2018 		result += wi[m] * p;
2019 	}
2020 	return result;
2021 }
2022 
sampleLinear2D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,const IVec3 & offset)2023 static Vec4 sampleLinear2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
2024 {
2025 	int w = access.getWidth();
2026 	int h = access.getHeight();
2027 
2028 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2029 	int x1 = x0+1;
2030 	int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
2031 	int y1 = y0+1;
2032 
2033 	int i0 = wrap(sampler.wrapS, x0, w);
2034 	int i1 = wrap(sampler.wrapS, x1, w);
2035 	int j0 = wrap(sampler.wrapT, y0, h);
2036 	int j1 = wrap(sampler.wrapT, y1, h);
2037 
2038 	float a = deFloatFrac(u-0.5f);
2039 	float b = deFloatFrac(v-0.5f);
2040 
2041 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
2042 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
2043 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
2044 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
2045 
2046 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2047 	Vec4 p00 = (i0UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, offset.z());
2048 	Vec4 p10 = (i1UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, offset.z());
2049 	Vec4 p01 = (i0UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, offset.z());
2050 	Vec4 p11 = (i1UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, offset.z());
2051 
2052 	// Interpolate.
2053 	return (p00*(1.0f-a)*(1.0f-b)) +
2054 		   (p10*(     a)*(1.0f-b)) +
2055 		   (p01*(1.0f-a)*(     b)) +
2056 		   (p11*(     a)*(     b));
2057 }
2058 
sampleCubic2D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,const IVec3 & offset)2059 static Vec4 sampleCubic2D(const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
2060 {
2061 	int width	= access.getWidth();
2062 	int height	= access.getHeight();
2063 
2064 	tcu::IVec4 x, y, i, j;
2065 
2066 	x[0] = deFloorFloatToInt32(u - 1.5f) + offset.x();
2067 	x[1] = x[0] + 1;
2068 	x[2] = x[1] + 1;
2069 	x[3] = x[2] + 1;
2070 	y[0] = deFloorFloatToInt32(v - 1.5f) + offset.y();
2071 	y[1] = y[0] + 1;
2072 	y[2] = y[1] + 1;
2073 	y[3] = y[2] + 1;
2074 
2075 	for (deUint32 m = 0; m < 4; ++m)
2076 		i[m] = wrap(sampler.wrapS, x[m], width);
2077 	for (deUint32 n = 0; n < 4; ++n)
2078 		j[n] = wrap(sampler.wrapT, y[n], height);
2079 
2080 	bool iUseBorder[4], jUseBorder[4];
2081 	for (deUint32 m = 0; m < 4; ++m)
2082 		iUseBorder[m] = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i[m], 0, width);
2083 	for (deUint32 n = 0; n < 4; ++n)
2084 		jUseBorder[n] = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j[n], 0, height);
2085 
2086 	// Catmull-Rom basis matrix
2087 	static const float crValues[16] = {	0.0f,	1.0f,	0.0f,	0.0f,
2088 										-0.5f,	0.0f,	0.5f,	0.0f,
2089 										1.0f,	-2.5f,	2.0f,	-0.5f,
2090 										-0.5f,	1.5f,	-1.5f,	0.5f };
2091 	static const tcu::Mat4 crBasis(crValues);
2092 
2093 	float		a		= deFloatFrac(u - 0.5f);
2094 	float		b		= deFloatFrac(v - 0.5f);
2095 	tcu::Vec4	alpha	(1, a, a*a, a*a*a);
2096 	tcu::Vec4	beta	(1, b, b*b, b*b*b);
2097 	tcu::Vec4	wi		= alpha * crBasis;
2098 	tcu::Vec4	wj		= beta  * crBasis;
2099 
2100 	tcu::Vec4 result(0.0f, 0.0f, 0.0f, 0.0f);
2101 	for (deUint32 n = 0; n < 4; ++n)
2102 		for (deUint32 m = 0; m < 4; ++m)
2103 		{
2104 			tcu::Vec4 p = (iUseBorder[m] || jUseBorder[n]) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i[m], j[n], offset.z());
2105 			result += wi[m] * wj[n] * p;
2106 		}
2107 	return result;
2108 }
2109 
sampleLinear1DCompare(const ConstPixelBufferAccess & access,const Sampler & sampler,float ref,float u,const IVec2 & offset,bool isFixedPointDepthFormat)2110 static float sampleLinear1DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, const IVec2& offset, bool isFixedPointDepthFormat)
2111 {
2112 	int w = access.getWidth();
2113 
2114 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2115 	int x1 = x0+1;
2116 
2117 	int i0 = wrap(sampler.wrapS, x0, w);
2118 	int i1 = wrap(sampler.wrapS, x1, w);
2119 
2120 	float a = deFloatFrac(u-0.5f);
2121 
2122 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
2123 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
2124 
2125 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2126 	Vec4 p0Clr = i0UseBorder  ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, offset.y(), 0);
2127 	Vec4 p1Clr = i1UseBorder  ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, offset.y(), 0);
2128 
2129 	// Execute comparisons.
2130 	float p0 = execCompare(p0Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2131 	float p1 = execCompare(p1Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2132 
2133 	// Interpolate.
2134 	return (p0 * (1.0f - a)) + (p1 * a);
2135 }
2136 
sampleLinear2DCompare(const ConstPixelBufferAccess & access,const Sampler & sampler,float ref,float u,float v,const IVec3 & offset,bool isFixedPointDepthFormat)2137 static float sampleLinear2DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, float v, const IVec3& offset, bool isFixedPointDepthFormat)
2138 {
2139 	int w = access.getWidth();
2140 	int h = access.getHeight();
2141 
2142 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2143 	int x1 = x0+1;
2144 	int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
2145 	int y1 = y0+1;
2146 
2147 	int i0 = wrap(sampler.wrapS, x0, w);
2148 	int i1 = wrap(sampler.wrapS, x1, w);
2149 	int j0 = wrap(sampler.wrapT, y0, h);
2150 	int j1 = wrap(sampler.wrapT, y1, h);
2151 
2152 	float a = deFloatFrac(u-0.5f);
2153 	float b = deFloatFrac(v-0.5f);
2154 
2155 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
2156 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
2157 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
2158 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
2159 
2160 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2161 	Vec4 p00Clr = (i0UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, offset.z());
2162 	Vec4 p10Clr = (i1UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, offset.z());
2163 	Vec4 p01Clr = (i0UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, offset.z());
2164 	Vec4 p11Clr = (i1UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, offset.z());
2165 
2166 	// Execute comparisons.
2167 	float p00 = execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2168 	float p10 = execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2169 	float p01 = execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2170 	float p11 = execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2171 
2172 	// Interpolate.
2173 	return (p00*(1.0f-a)*(1.0f-b)) +
2174 		   (p10*(     a)*(1.0f-b)) +
2175 		   (p01*(1.0f-a)*(     b)) +
2176 		   (p11*(     a)*(     b));
2177 }
2178 
sampleLinear3D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,float w,const IVec3 & offset)2179 static Vec4 sampleLinear3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
2180 {
2181 	int width	= access.getWidth();
2182 	int height	= access.getHeight();
2183 	int depth	= access.getDepth();
2184 
2185 	int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2186 	int x1 = x0+1;
2187 	int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
2188 	int y1 = y0+1;
2189 	int z0 = deFloorFloatToInt32(w-0.5f)+offset.z();
2190 	int z1 = z0+1;
2191 
2192 	int i0 = wrap(sampler.wrapS, x0, width);
2193 	int i1 = wrap(sampler.wrapS, x1, width);
2194 	int j0 = wrap(sampler.wrapT, y0, height);
2195 	int j1 = wrap(sampler.wrapT, y1, height);
2196 	int k0 = wrap(sampler.wrapR, z0, depth);
2197 	int k1 = wrap(sampler.wrapR, z1, depth);
2198 
2199 	float a = deFloatFrac(u-0.5f);
2200 	float b = deFloatFrac(v-0.5f);
2201 	float c = deFloatFrac(w-0.5f);
2202 
2203 	bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, width);
2204 	bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, width);
2205 	bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, height);
2206 	bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, height);
2207 	bool k0UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k0, 0, depth);
2208 	bool k1UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k1, 0, depth);
2209 
2210 	// Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2211 	Vec4 p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, k0);
2212 	Vec4 p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, k0);
2213 	Vec4 p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, k0);
2214 	Vec4 p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, k0);
2215 	Vec4 p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, k1);
2216 	Vec4 p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, k1);
2217 	Vec4 p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, k1);
2218 	Vec4 p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, k1);
2219 
2220 	// Interpolate.
2221 	return (p000*(1.0f-a)*(1.0f-b)*(1.0f-c)) +
2222 		   (p100*(     a)*(1.0f-b)*(1.0f-c)) +
2223 		   (p010*(1.0f-a)*(     b)*(1.0f-c)) +
2224 		   (p110*(     a)*(     b)*(1.0f-c)) +
2225 		   (p001*(1.0f-a)*(1.0f-b)*(     c)) +
2226 		   (p101*(     a)*(1.0f-b)*(     c)) +
2227 		   (p011*(1.0f-a)*(     b)*(     c)) +
2228 		   (p111*(     a)*(     b)*(     c));
2229 }
2230 
sampleCubic3D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,float w,const IVec3 & offset)2231 static Vec4 sampleCubic3D(const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
2232 {
2233 	int width	= access.getWidth();
2234 	int height	= access.getHeight();
2235 	int depth	= access.getDepth();
2236 
2237 	tcu::IVec4 x, y, z, i, j, k;
2238 
2239 	x[0] = deFloorFloatToInt32(u - 1.5f) + offset.x();
2240 	x[1] = x[0] + 1;
2241 	x[2] = x[1] + 1;
2242 	x[3] = x[2] + 1;
2243 	y[0] = deFloorFloatToInt32(v - 1.5f) + offset.y();
2244 	y[1] = y[0] + 1;
2245 	y[2] = y[1] + 1;
2246 	y[3] = y[2] + 1;
2247 	z[0] = deFloorFloatToInt32(w - 1.5f) + offset.z();
2248 	z[1] = z[0] + 1;
2249 	z[2] = z[1] + 1;
2250 	z[3] = z[2] + 1;
2251 
2252 	for (deUint32 m = 0; m < 4; ++m)
2253 		i[m] = wrap(sampler.wrapS, x[m], width);
2254 	for (deUint32 n = 0; n < 4; ++n)
2255 		j[n] = wrap(sampler.wrapT, y[n], height);
2256 	for (deUint32 o = 0; o < 4; ++o)
2257 		k[o] = wrap(sampler.wrapR, k[o], depth);
2258 
2259 	bool iUseBorder[4], jUseBorder[4], kUseBorder[4];
2260 	for (deUint32 m = 0; m < 4; ++m)
2261 		iUseBorder[m] = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i[m], 0, width);
2262 	for (deUint32 n = 0; n < 4; ++n)
2263 		jUseBorder[n] = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j[n], 0, height);
2264 	for (deUint32 o = 0; o < 4; ++o)
2265 		kUseBorder[o] = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k[o], 0, depth);
2266 
2267 	// Catmull-Rom basis matrix
2268 	static const float crValues[16] = {	0.0f,	1.0f,	0.0f,	0.0f,
2269 										-0.5f,	0.0f,	0.5f,	0.0f,
2270 										1.0f,	-2.5f,	2.0f,	-0.5f,
2271 										-0.5f,	1.5f,	-1.5f,	0.5f };
2272 	static const tcu::Mat4 crBasis(crValues);
2273 
2274 	float		a		= deFloatFrac(u - 0.5f);
2275 	float		b		= deFloatFrac(v - 0.5f);
2276 	float		c		= deFloatFrac(w - 0.5f);
2277 	tcu::Vec4	alpha	(1, a, a*a, a*a*a);
2278 	tcu::Vec4	beta	(1, b, b*b, b*b*b);
2279 	tcu::Vec4	gamma	(1, c, c*c, c*c*c);
2280 	tcu::Vec4	wi		= alpha * crBasis;
2281 	tcu::Vec4	wj		= beta  * crBasis;
2282 	tcu::Vec4	wk		= gamma * crBasis;
2283 
2284 	tcu::Vec4 result(0.0f, 0.0f, 0.0f, 0.0f);
2285 	for (deUint32 o = 0; o < 4; ++o)
2286 		for (deUint32 n = 0; n < 4; ++n)
2287 			for (deUint32 m = 0; m < 4; ++m)
2288 			{
2289 				tcu::Vec4 p = (iUseBorder[m] || jUseBorder[n] || kUseBorder[o]) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i[m], j[n], k[o]);
2290 				result += wi[m] * wj[n] * wk[o] * p;
2291 			}
2292 	return result;
2293 }
2294 
sample1D(const Sampler & sampler,Sampler::FilterMode filter,float s,int level) const2295 Vec4 ConstPixelBufferAccess::sample1D (const Sampler& sampler, Sampler::FilterMode filter, float s, int level) const
2296 {
2297 	// check selected layer exists
2298 	DE_ASSERT(de::inBounds(level, 0, m_size.y()));
2299 
2300 	return sample1DOffset(sampler, filter, s, tcu::IVec2(0, level));
2301 }
2302 
sample2D(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,int depth) const2303 Vec4 ConstPixelBufferAccess::sample2D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, int depth) const
2304 {
2305 	// check selected layer exists
2306 	DE_ASSERT(de::inBounds(depth, 0, m_size.z()));
2307 
2308 	return sample2DOffset(sampler, filter, s, t, tcu::IVec3(0, 0, depth));
2309 }
2310 
sample3D(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,float r) const2311 Vec4 ConstPixelBufferAccess::sample3D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r) const
2312 {
2313 	return sample3DOffset(sampler, filter, s, t, r, tcu::IVec3(0, 0, 0));
2314 }
2315 
sample1DOffset(const Sampler & sampler,Sampler::FilterMode filter,float s,const IVec2 & offset) const2316 Vec4 ConstPixelBufferAccess::sample1DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, const IVec2& offset) const
2317 {
2318 	// check selected layer exists
2319 	// \note offset.x is X offset, offset.y is the selected layer
2320 	DE_ASSERT(de::inBounds(offset.y(), 0, m_size.y()));
2321 
2322 	// Non-normalized coordinates.
2323 	float u = s;
2324 
2325 	if (sampler.normalizedCoords)
2326 		u = unnormalize(sampler.wrapS, s, m_size.x());
2327 
2328 	switch (filter)
2329 	{
2330 		case Sampler::NEAREST:	return sampleNearest1D	(*this, sampler, u, offset);
2331 		case Sampler::LINEAR:	return sampleLinear1D	(*this, sampler, u, offset);
2332 		case Sampler::CUBIC:	return sampleCubic1D	(*this, sampler, u, offset);
2333 		default:
2334 			DE_ASSERT(DE_FALSE);
2335 			return Vec4(0.0f);
2336 	}
2337 }
2338 
sample2DOffset(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,const IVec3 & offset) const2339 Vec4 ConstPixelBufferAccess::sample2DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, const IVec3& offset) const
2340 {
2341 	// check selected layer exists
2342 	// \note offset.xy is the XY offset, offset.z is the selected layer
2343 	DE_ASSERT(de::inBounds(offset.z(), 0, m_size.z()));
2344 
2345 	// Non-normalized coordinates.
2346 	float u = s;
2347 	float v = t;
2348 
2349 	if (sampler.normalizedCoords)
2350 	{
2351 		u = unnormalize(sampler.wrapS, s, m_size.x());
2352 		v = unnormalize(sampler.wrapT, t, m_size.y());
2353 	}
2354 
2355 	switch (filter)
2356 	{
2357 		case Sampler::NEAREST:	return sampleNearest2D	(*this, sampler, u, v, offset);
2358 		case Sampler::LINEAR:	return sampleLinear2D	(*this, sampler, u, v, offset);
2359 		case Sampler::CUBIC:	return sampleCubic2D	(*this, sampler, u, v, offset);
2360 		default:
2361 			DE_ASSERT(DE_FALSE);
2362 			return Vec4(0.0f);
2363 	}
2364 }
2365 
sample3DOffset(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,float r,const IVec3 & offset) const2366 Vec4 ConstPixelBufferAccess::sample3DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r, const IVec3& offset) const
2367 {
2368 	// Non-normalized coordinates.
2369 	float u = s;
2370 	float v = t;
2371 	float w = r;
2372 
2373 	if (sampler.normalizedCoords)
2374 	{
2375 		u = unnormalize(sampler.wrapS, s, m_size.x());
2376 		v = unnormalize(sampler.wrapT, t, m_size.y());
2377 		w = unnormalize(sampler.wrapR, r, m_size.z());
2378 	}
2379 
2380 	switch (filter)
2381 	{
2382 		case Sampler::NEAREST:	return sampleNearest3D	(*this, sampler, u, v, w, offset);
2383 		case Sampler::LINEAR:	return sampleLinear3D	(*this, sampler, u, v, w, offset);
2384 		case Sampler::CUBIC:	return sampleCubic3D	(*this, sampler, u, v, w, offset);
2385 		default:
2386 			DE_ASSERT(DE_FALSE);
2387 			return Vec4(0.0f);
2388 	}
2389 }
2390 
sample1DCompare(const Sampler & sampler,Sampler::FilterMode filter,float ref,float s,const IVec2 & offset) const2391 float ConstPixelBufferAccess::sample1DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, const IVec2& offset) const
2392 {
2393 	// check selected layer exists
2394 	// \note offset.x is X offset, offset.y is the selected layer
2395 	DE_ASSERT(de::inBounds(offset.y(), 0, m_size.y()));
2396 
2397 	// Format information for comparison function
2398 	const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2399 
2400 	// Non-normalized coordinates.
2401 	float u = s;
2402 
2403 	if (sampler.normalizedCoords)
2404 		u = unnormalize(sampler.wrapS, s, m_size.x());
2405 
2406 	switch (filter)
2407 	{
2408 		case Sampler::NEAREST:	return execCompare(sampleNearest1D(*this, sampler, u, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2409 		case Sampler::LINEAR:	return sampleLinear1DCompare(*this, sampler, ref, u, offset, isFixedPointDepth);
2410 		default:
2411 			DE_ASSERT(DE_FALSE);
2412 			return 0.0f;
2413 	}
2414 }
2415 
sample2DCompare(const Sampler & sampler,Sampler::FilterMode filter,float ref,float s,float t,const IVec3 & offset) const2416 float ConstPixelBufferAccess::sample2DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, float t, const IVec3& offset) const
2417 {
2418 	// check selected layer exists
2419 	// \note offset.xy is XY offset, offset.z is the selected layer
2420 	DE_ASSERT(de::inBounds(offset.z(), 0, m_size.z()));
2421 
2422 	// Format information for comparison function
2423 	const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2424 
2425 	// Non-normalized coordinates.
2426 	float u = s;
2427 	float v = t;
2428 
2429 	if (sampler.normalizedCoords)
2430 	{
2431 		u = unnormalize(sampler.wrapS, s, m_size.x());
2432 		v = unnormalize(sampler.wrapT, t, m_size.y());
2433 	}
2434 
2435 	switch (filter)
2436 	{
2437 		case Sampler::NEAREST:	return execCompare(sampleNearest2D(*this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2438 		case Sampler::LINEAR:	return sampleLinear2DCompare(*this, sampler, ref, u, v, offset, isFixedPointDepth);
2439 		default:
2440 			DE_ASSERT(DE_FALSE);
2441 			return 0.0f;
2442 	}
2443 }
2444 
TextureLevel(void)2445 TextureLevel::TextureLevel (void)
2446 	: m_format	()
2447 	, m_size	(0)
2448 {
2449 }
2450 
TextureLevel(const TextureFormat & format)2451 TextureLevel::TextureLevel (const TextureFormat& format)
2452 	: m_format	(format)
2453 	, m_size	(0)
2454 {
2455 }
2456 
TextureLevel(const TextureFormat & format,int width,int height,int depth)2457 TextureLevel::TextureLevel (const TextureFormat& format, int width, int height, int depth)
2458 	: m_format	(format)
2459 	, m_size	(0)
2460 {
2461 	setSize(width, height, depth);
2462 }
2463 
~TextureLevel(void)2464 TextureLevel::~TextureLevel (void)
2465 {
2466 }
2467 
setStorage(const TextureFormat & format,int width,int height,int depth)2468 void TextureLevel::setStorage (const TextureFormat& format, int width, int height, int depth)
2469 {
2470 	m_format = format;
2471 	setSize(width, height, depth);
2472 }
2473 
setSize(int width,int height,int depth)2474 void TextureLevel::setSize (int width, int height, int depth)
2475 {
2476 	int pixelSize = m_format.getPixelSize();
2477 
2478 	m_size = IVec3(width, height, depth);
2479 
2480 	m_data.setStorage(m_size.x() * m_size.y() * m_size.z() * pixelSize);
2481 }
2482 
sampleLevelArray1D(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,int depth,float lod)2483 Vec4 sampleLevelArray1D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, int depth, float lod)
2484 {
2485 	return sampleLevelArray1DOffset(levels, numLevels, sampler, s, lod, IVec2(0, depth)); // y-offset in 1D textures is layer selector
2486 }
2487 
sampleLevelArray2D(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,int depth,float lod,bool es2,ImageViewMinLodParams * minLodParams)2488 Vec4 sampleLevelArray2D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, int depth, float lod, bool es2, ImageViewMinLodParams* minLodParams)
2489 {
2490 	return sampleLevelArray2DOffset(levels, numLevels, sampler, s, t, lod, IVec3(0, 0, depth), es2, minLodParams); // z-offset in 2D textures is layer selector
2491 }
2492 
sampleLevelArray3D(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,float r,float lod,ImageViewMinLodParams * minLodParams)2493 Vec4 sampleLevelArray3D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod, ImageViewMinLodParams* minLodParams)
2494 {
2495 	return sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, IVec3(0, 0, 0), minLodParams);
2496 }
2497 
sampleLevelArray1DOffset(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float lod,const IVec2 & offset)2498 Vec4 sampleLevelArray1DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float lod, const IVec2& offset)
2499 {
2500 	bool					magnified	= lod <= sampler.lodThreshold;
2501 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
2502 
2503 	switch (filterMode)
2504 	{
2505 		case Sampler::NEAREST:	return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2506 		case Sampler::LINEAR:	return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2507 
2508 		case Sampler::NEAREST_MIPMAP_NEAREST:
2509 		case Sampler::LINEAR_MIPMAP_NEAREST:
2510 		{
2511 			int					maxLevel	= (int)numLevels-1;
2512 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2513 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2514 
2515 			return levels[level].sample1DOffset(sampler, levelFilter, s, offset);
2516 		}
2517 
2518 		case Sampler::NEAREST_MIPMAP_LINEAR:
2519 		case Sampler::LINEAR_MIPMAP_LINEAR:
2520 		{
2521 			int					maxLevel	= (int)numLevels-1;
2522 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2523 			int					level1		= de::min(maxLevel, level0 + 1);
2524 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2525 			float				f			= deFloatFrac(lod);
2526 			tcu::Vec4			t0			= levels[level0].sample1DOffset(sampler, levelFilter, s, offset);
2527 			tcu::Vec4			t1			= levels[level1].sample1DOffset(sampler, levelFilter, s, offset);
2528 
2529 			return t0*(1.0f - f) + t1*f;
2530 		}
2531 
2532 		default:
2533 			DE_ASSERT(DE_FALSE);
2534 			return Vec4(0.0f);
2535 	}
2536 }
2537 
sampleLevelArray2DOffset(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,float lod,const IVec3 & offset,bool es2,ImageViewMinLodParams * minLodParams)2538 Vec4 sampleLevelArray2DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float lod, const IVec3& offset, bool es2, ImageViewMinLodParams* minLodParams)
2539 {
2540 	bool					magnified;
2541 	// minLodRelative is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
2542 	// The value is relative to baseLevel as the Texture*View was created as the baseLevel being level[0].
2543 	const float				minLodRelative	= (minLodParams != DE_NULL) ? getImageViewMinLod(minLodParams->minLod) - (float)minLodParams->baseLevel : 0.0f;
2544 
2545 	if (es2 && sampler.magFilter == Sampler::LINEAR &&
2546 		(sampler.minFilter == Sampler::NEAREST_MIPMAP_NEAREST || sampler.minFilter == Sampler::NEAREST_MIPMAP_LINEAR))
2547 		magnified = lod <= 0.5;
2548 	else
2549 		magnified = lod <= sampler.lodThreshold;
2550 
2551 	// VK_EXT_image_view_min_lod: Integer Texel Coordinates case (with robustness2 supported)
2552 	if (minLodParams != DE_NULL && minLodParams->intTexCoord)
2553 	{
2554 		if (lod < deFloatFloor(minLodRelative) || lod >= (float)numLevels)
2555 			return Vec4(0.0f);
2556 
2557 		if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
2558 			return Vec4(0.0f);
2559 	}
2560 
2561 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
2562 	switch (filterMode)
2563 	{
2564 		case Sampler::NEAREST:
2565 		case Sampler::LINEAR:
2566 		case Sampler::CUBIC:
2567 		{
2568 			bool isLinearMipmapMode	= magnified && tcu::isSamplerMipmapModeLinear(sampler.minFilter);
2569 			const int maxLevel		= (int)numLevels - 1;
2570 			const int level0		= isLinearMipmapMode ? (int)deFloatFloor(minLodRelative) : deClamp32((int)deFloatCeil(minLodRelative + 0.5f) - 1, 0, maxLevel);
2571 			tcu::Vec4 t0			= levels[level0].sample2DOffset(sampler, filterMode, s, t, offset);
2572 
2573 			if (!isLinearMipmapMode)
2574 				return t0;
2575 
2576 			const float frac		= deFloatFrac(minLodRelative);
2577 			const int level1		= de::min(level0 + 1, maxLevel);
2578 			tcu::Vec4 t1			= levels[level1].sample2DOffset(sampler, filterMode, s, t, offset);
2579 			return t0*(1.0f - frac) + t1*frac;
2580 		}
2581 
2582 		case Sampler::NEAREST_MIPMAP_NEAREST:
2583 		case Sampler::LINEAR_MIPMAP_NEAREST:
2584 		case Sampler::CUBIC_MIPMAP_NEAREST:
2585 		{
2586 			if (minLodParams != DE_NULL && !minLodParams->intTexCoord)
2587 				lod = de::max(lod, minLodRelative);
2588 
2589 			int					maxLevel	= (int)numLevels-1;
2590 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2591 			Sampler::FilterMode	levelFilter;
2592 			switch (filterMode)
2593 			{
2594 			case Sampler::NEAREST_MIPMAP_NEAREST:	levelFilter = Sampler::NEAREST; break;
2595 			case Sampler::LINEAR_MIPMAP_NEAREST:	levelFilter = Sampler::LINEAR; break;
2596 			case Sampler::CUBIC_MIPMAP_NEAREST:		levelFilter = Sampler::CUBIC; break;
2597 			default:
2598 				DE_ASSERT(DE_FALSE);
2599 				return Vec4(0.0f);
2600 			}
2601 
2602 			return levels[level].sample2DOffset(sampler, levelFilter, s, t, offset);
2603 		}
2604 
2605 		case Sampler::NEAREST_MIPMAP_LINEAR:
2606 		case Sampler::LINEAR_MIPMAP_LINEAR:
2607 		case Sampler::CUBIC_MIPMAP_LINEAR:
2608 		{
2609 			if (minLodParams != DE_NULL && !minLodParams->intTexCoord)
2610 				lod = de::max(lod, minLodRelative);
2611 
2612 			int					maxLevel	= (int)numLevels-1;
2613 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2614 			int					level1		= de::min(maxLevel, level0 + 1);
2615 			Sampler::FilterMode	levelFilter;
2616 			switch (filterMode)
2617 			{
2618 			case Sampler::NEAREST_MIPMAP_LINEAR:	levelFilter = Sampler::NEAREST; break;
2619 			case Sampler::LINEAR_MIPMAP_LINEAR:		levelFilter = Sampler::LINEAR; break;
2620 			case Sampler::CUBIC_MIPMAP_LINEAR:		levelFilter = Sampler::CUBIC; break;
2621 			default:
2622 				DE_ASSERT(DE_FALSE);
2623 				return Vec4(0.0f);
2624 			}
2625 			float				f			= deFloatFrac(lod);
2626 			tcu::Vec4			t0			= levels[level0].sample2DOffset(sampler, levelFilter, s, t, offset);
2627 			tcu::Vec4			t1			= levels[level1].sample2DOffset(sampler, levelFilter, s, t, offset);
2628 
2629 			return t0*(1.0f - f) + t1*f;
2630 		}
2631 
2632 		default:
2633 			DE_ASSERT(DE_FALSE);
2634 			return Vec4(0.0f);
2635 	}
2636 }
2637 
sampleLevelArray3DOffset(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,float r,float lod,const IVec3 & offset,ImageViewMinLodParams * minLodParams)2638 Vec4 sampleLevelArray3DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod, const IVec3& offset, ImageViewMinLodParams* minLodParams)
2639 {
2640 	// minLodRelative is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
2641 	// The value is relative to baseLevel as the Texture*View was created as the baseLevel being level[0].
2642 	const float				minLodRelative	= (minLodParams != DE_NULL) ? getImageViewMinLod(minLodParams->minLod) - (float)minLodParams->baseLevel : 0.0f;
2643 	bool					magnified	= lod <= sampler.lodThreshold;
2644 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
2645 
2646 	// VK_EXT_image_view_min_lod: Integer Texel Coordinates case (with robustness2 supported)
2647 	if (minLodParams != DE_NULL && minLodParams->intTexCoord)
2648 	{
2649 		if (lod < deFloatFloor(minLodRelative) || lod >= (float)numLevels)
2650 			return Vec4(0.0f);
2651 
2652 		if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
2653 			return Vec4(0.0f);
2654 	}
2655 
2656 	switch (filterMode)
2657 	{
2658 		case Sampler::NEAREST:
2659 		case Sampler::LINEAR:
2660 		{
2661 			bool isLinearMipmapMode	= magnified && tcu::isSamplerMipmapModeLinear(sampler.minFilter);
2662 			const int maxLevel		= (int)numLevels - 1;
2663 			const int level0		= isLinearMipmapMode ? (int)deFloatFloor(minLodRelative) : deClamp32((int)deFloatCeil(minLodRelative + 0.5f) - 1, 0, maxLevel);
2664 			tcu::Vec4 t0			= levels[level0].sample3DOffset(sampler, filterMode, s, t, r, offset);
2665 
2666 			if (!isLinearMipmapMode)
2667 				return t0;
2668 
2669 			const float frac		= deFloatFrac(minLodRelative);
2670 			const int level1		= de::min(level0 + 1, maxLevel);
2671 			tcu::Vec4 t1			= levels[level1].sample3DOffset(sampler, filterMode, s, t, r, offset);
2672 			return t0*(1.0f - frac) + t1*frac;
2673 		}
2674 
2675 		case Sampler::NEAREST_MIPMAP_NEAREST:
2676 		case Sampler::LINEAR_MIPMAP_NEAREST:
2677 		{
2678 			if (minLodParams != DE_NULL && !minLodParams->intTexCoord)
2679 				lod = de::max(lod, minLodRelative);
2680 
2681 			int					maxLevel	= (int)numLevels-1;
2682 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2683 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2684 
2685 			return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2686 		}
2687 
2688 		case Sampler::NEAREST_MIPMAP_LINEAR:
2689 		case Sampler::LINEAR_MIPMAP_LINEAR:
2690 		{
2691 			if (minLodParams != DE_NULL && !minLodParams->intTexCoord)
2692 				lod = de::max(lod, minLodRelative);
2693 
2694 			int					maxLevel	= (int)numLevels-1;
2695 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2696 			int					level1		= de::min(maxLevel, level0 + 1);
2697 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2698 			float				f			= deFloatFrac(lod);
2699 			tcu::Vec4			t0			= levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2700 			tcu::Vec4			t1			= levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2701 
2702 			return t0*(1.0f - f) + t1*f;
2703 		}
2704 
2705 		default:
2706 			DE_ASSERT(DE_FALSE);
2707 			return Vec4(0.0f);
2708 	}
2709 }
2710 
sampleLevelArray1DCompare(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float ref,float s,float lod,const IVec2 & offset)2711 float sampleLevelArray1DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float lod, const IVec2& offset)
2712 {
2713 	bool					magnified	= lod <= sampler.lodThreshold;
2714 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
2715 
2716 	switch (filterMode)
2717 	{
2718 		case Sampler::NEAREST:	return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
2719 		case Sampler::LINEAR:	return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
2720 
2721 		case Sampler::NEAREST_MIPMAP_NEAREST:
2722 		case Sampler::LINEAR_MIPMAP_NEAREST:
2723 		{
2724 			int					maxLevel	= (int)numLevels-1;
2725 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2726 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2727 
2728 			return levels[level].sample1DCompare(sampler, levelFilter, ref, s, offset);
2729 		}
2730 
2731 		case Sampler::NEAREST_MIPMAP_LINEAR:
2732 		case Sampler::LINEAR_MIPMAP_LINEAR:
2733 		{
2734 			int					maxLevel	= (int)numLevels-1;
2735 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2736 			int					level1		= de::min(maxLevel, level0 + 1);
2737 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2738 			float				f			= deFloatFrac(lod);
2739 			float				t0			= levels[level0].sample1DCompare(sampler, levelFilter, ref, s, offset);
2740 			float				t1			= levels[level1].sample1DCompare(sampler, levelFilter, ref, s, offset);
2741 
2742 			return t0*(1.0f - f) + t1*f;
2743 		}
2744 
2745 		default:
2746 			DE_ASSERT(DE_FALSE);
2747 			return 0.0f;
2748 	}
2749 }
2750 
sampleLevelArray2DCompare(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float ref,float s,float t,float lod,const IVec3 & offset)2751 float sampleLevelArray2DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float t, float lod, const IVec3& offset)
2752 {
2753 	bool					magnified	= lod <= sampler.lodThreshold;
2754 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
2755 
2756 	switch (filterMode)
2757 	{
2758 		case Sampler::NEAREST:	return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
2759 		case Sampler::LINEAR:	return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
2760 
2761 		case Sampler::NEAREST_MIPMAP_NEAREST:
2762 		case Sampler::LINEAR_MIPMAP_NEAREST:
2763 		{
2764 			int					maxLevel	= (int)numLevels-1;
2765 			int					level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2766 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2767 
2768 			return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2769 		}
2770 
2771 		case Sampler::NEAREST_MIPMAP_LINEAR:
2772 		case Sampler::LINEAR_MIPMAP_LINEAR:
2773 		{
2774 			int					maxLevel	= (int)numLevels-1;
2775 			int					level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2776 			int					level1		= de::min(maxLevel, level0 + 1);
2777 			Sampler::FilterMode	levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2778 			float				f			= deFloatFrac(lod);
2779 			float				t0			= levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2780 			float				t1			= levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2781 
2782 			return t0*(1.0f - f) + t1*f;
2783 		}
2784 
2785 		default:
2786 			DE_ASSERT(DE_FALSE);
2787 			return 0.0f;
2788 	}
2789 }
2790 
fetchGatherArray2DOffsets(const ConstPixelBufferAccess & src,const Sampler & sampler,float s,float t,int depth,int componentNdx,const IVec2 (& offsets)[4])2791 static Vec4 fetchGatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2792 {
2793 	DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2794 
2795 	const int		w	= src.getWidth();
2796 	const int		h	= src.getHeight();
2797 	const float		u	= unnormalize(sampler.wrapS, s, w);
2798 	const float		v	= unnormalize(sampler.wrapT, t, h);
2799 	const int		x0	= deFloorFloatToInt32(u-0.5f);
2800 	const int		y0	= deFloorFloatToInt32(v-0.5f);
2801 
2802 	Vec4			result;
2803 
2804 	for (int i = 0; i < 4; i++)
2805 	{
2806 		const int	sampleX	= wrap(sampler.wrapS, x0 + offsets[i].x(), w);
2807 		const int	sampleY	= wrap(sampler.wrapT, y0 + offsets[i].y(), h);
2808 		Vec4		pixel;
2809 
2810 		if (deInBounds32(sampleX, 0, w) && deInBounds32(sampleY, 0, h))
2811 			pixel = lookup(src, sampleX, sampleY, depth);
2812 		else
2813 			pixel = lookupBorder(src.getFormat(), sampler);
2814 
2815 		result[i] = pixel[componentNdx];
2816 	}
2817 
2818 	return result;
2819 }
2820 
gatherArray2DOffsets(const ConstPixelBufferAccess & src,const Sampler & sampler,float s,float t,int depth,int componentNdx,const IVec2 (& offsets)[4])2821 Vec4 gatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2822 {
2823 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
2824 	DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2825 
2826 	return fetchGatherArray2DOffsets(src, sampler, s, t, depth, componentNdx, offsets);
2827 }
2828 
gatherArray2DOffsetsCompare(const ConstPixelBufferAccess & src,const Sampler & sampler,float ref,float s,float t,int depth,const IVec2 (& offsets)[4])2829 Vec4 gatherArray2DOffsetsCompare (const ConstPixelBufferAccess& src, const Sampler& sampler, float ref, float s, float t, int depth, const IVec2 (&offsets)[4])
2830 {
2831 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
2832 	DE_ASSERT(src.getFormat().order == TextureFormat::D || src.getFormat().order == TextureFormat::DS);
2833 	DE_ASSERT(sampler.compareChannel == 0);
2834 
2835 	const bool	isFixedPoint	= isFixedPointDepthTextureFormat(src.getFormat());
2836 	const Vec4	gathered		= fetchGatherArray2DOffsets(src, sampler, s, t, depth, 0 /* component 0: depth */, offsets);
2837 	Vec4		result;
2838 
2839 	for (int i = 0; i < 4; i++)
2840 		result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
2841 
2842 	return result;
2843 }
2844 
sampleCubeSeamlessNearest(const ConstPixelBufferAccess & faceAccess,const Sampler & sampler,float s,float t,int depth)2845 static Vec4 sampleCubeSeamlessNearest (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float s, float t, int depth)
2846 {
2847 	Sampler clampingSampler = sampler;
2848 	clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
2849 	clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
2850 	return faceAccess.sample2D(clampingSampler, Sampler::NEAREST, s, t, depth);
2851 }
2852 
selectCubeFace(const Vec3 & coords)2853 CubeFace selectCubeFace (const Vec3& coords)
2854 {
2855 	const float	x	= coords.x();
2856 	const float	y	= coords.y();
2857 	const float	z	= coords.z();
2858 	const float	ax	= deFloatAbs(x);
2859 	const float	ay	= deFloatAbs(y);
2860 	const float	az	= deFloatAbs(z);
2861 
2862 	if (ay < ax && az < ax)
2863 		return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2864 	else if (ax < ay && az < ay)
2865 		return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2866 	else if (ax < az && ay < az)
2867 		return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2868 	else
2869 	{
2870 		// Some of the components are equal. Use tie-breaking rule.
2871 		if (ax == ay)
2872 		{
2873 			if (ax < az)
2874 				return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2875 			else
2876 				return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2877 		}
2878 		else if (ax == az)
2879 		{
2880 			if (az < ay)
2881 				return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2882 			else
2883 				return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2884 		}
2885 		else if (ay == az)
2886 		{
2887 			if (ay < ax)
2888 				return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2889 			else
2890 				return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2891 		}
2892 		else
2893 			return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2894 	}
2895 }
2896 
projectToFace(CubeFace face,const Vec3 & coord)2897 Vec2 projectToFace (CubeFace face, const Vec3& coord)
2898 {
2899 	const float	rx		= coord.x();
2900 	const float	ry		= coord.y();
2901 	const float	rz		= coord.z();
2902 	float		sc		= 0.0f;
2903 	float		tc		= 0.0f;
2904 	float		ma		= 0.0f;
2905 	float		s;
2906 	float		t;
2907 
2908 	switch (face)
2909 	{
2910 		case CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break;
2911 		case CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break;
2912 		case CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break;
2913 		case CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break;
2914 		case CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break;
2915 		case CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break;
2916 		default:
2917 			DE_ASSERT(DE_FALSE);
2918 	}
2919 
2920 	if (fabs(ma) < FLT_EPSILON)
2921 	{
2922 		return Vec2(0.0f);
2923 	}
2924 
2925 	// Compute s, t
2926 	s = ((sc / ma) + 1.0f) / 2.0f;
2927 	t = ((tc / ma) + 1.0f) / 2.0f;
2928 
2929 	return Vec2(s, t);
2930 }
2931 
getCubeFaceCoords(const Vec3 & coords)2932 CubeFaceFloatCoords getCubeFaceCoords (const Vec3& coords)
2933 {
2934 	const CubeFace face = selectCubeFace(coords);
2935 	return CubeFaceFloatCoords(face, projectToFace(face, coords));
2936 }
2937 
2938 // Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceIntCoords with face set to the appropriate neighboring face and coords transformed accordingly.
2939 // \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face.
remapCubeEdgeCoords(const CubeFaceIntCoords & origCoords,int size)2940 CubeFaceIntCoords remapCubeEdgeCoords (const CubeFaceIntCoords& origCoords, int size)
2941 {
2942 	bool uInBounds = de::inBounds(origCoords.s, 0, size);
2943 	bool vInBounds = de::inBounds(origCoords.t, 0, size);
2944 
2945 	if (uInBounds && vInBounds)
2946 		return origCoords;
2947 
2948 	if (!uInBounds && !vInBounds)
2949 		return CubeFaceIntCoords(CUBEFACE_LAST, -1, -1);
2950 
2951 	IVec2 coords(wrap(Sampler::CLAMP_TO_BORDER, origCoords.s, size),
2952 				 wrap(Sampler::CLAMP_TO_BORDER, origCoords.t, size));
2953 	IVec3 canonizedCoords;
2954 
2955 	// Map the uv coordinates to canonized 3d coordinates.
2956 
2957 	switch (origCoords.face)
2958 	{
2959 		case CUBEFACE_NEGATIVE_X: canonizedCoords = IVec3(0,					size-1-coords.y(),	coords.x());			break;
2960 		case CUBEFACE_POSITIVE_X: canonizedCoords = IVec3(size-1,				size-1-coords.y(),	size-1-coords.x());		break;
2961 		case CUBEFACE_NEGATIVE_Y: canonizedCoords = IVec3(coords.x(),			0,					size-1-coords.y());		break;
2962 		case CUBEFACE_POSITIVE_Y: canonizedCoords = IVec3(coords.x(),			size-1,				coords.y());			break;
2963 		case CUBEFACE_NEGATIVE_Z: canonizedCoords = IVec3(size-1-coords.x(),	size-1-coords.y(),	0);						break;
2964 		case CUBEFACE_POSITIVE_Z: canonizedCoords = IVec3(coords.x(),			size-1-coords.y(),	size-1);				break;
2965 		default: DE_ASSERT(false);
2966 	}
2967 
2968 	// Find an appropriate face to re-map the coordinates to.
2969 
2970 	if (canonizedCoords.x() == -1)
2971 		return CubeFaceIntCoords(CUBEFACE_NEGATIVE_X, IVec2(canonizedCoords.z(), size-1-canonizedCoords.y()));
2972 
2973 	if (canonizedCoords.x() == size)
2974 		return CubeFaceIntCoords(CUBEFACE_POSITIVE_X, IVec2(size-1-canonizedCoords.z(), size-1-canonizedCoords.y()));
2975 
2976 	if (canonizedCoords.y() == -1)
2977 		return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Y, IVec2(canonizedCoords.x(), size-1-canonizedCoords.z()));
2978 
2979 	if (canonizedCoords.y() == size)
2980 		return CubeFaceIntCoords(CUBEFACE_POSITIVE_Y, IVec2(canonizedCoords.x(), canonizedCoords.z()));
2981 
2982 	if (canonizedCoords.z() == -1)
2983 		return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Z, IVec2(size-1-canonizedCoords.x(), size-1-canonizedCoords.y()));
2984 
2985 	if (canonizedCoords.z() == size)
2986 		return CubeFaceIntCoords(CUBEFACE_POSITIVE_Z, IVec2(canonizedCoords.x(), size-1-canonizedCoords.y()));
2987 
2988 	DE_ASSERT(false);
2989 	return CubeFaceIntCoords(CUBEFACE_LAST, IVec2(-1));
2990 }
2991 
getCubeLinearSamples(const ConstPixelBufferAccess (& faceAccesses)[CUBEFACE_LAST],CubeFace baseFace,float u,float v,int depth,Vec4 (& dst)[4])2992 static void getCubeLinearSamples (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, float u, float v, int depth, Vec4 (&dst)[4])
2993 {
2994 	DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2995 	int		size					= faceAccesses[0].getWidth();
2996 	int		x0						= deFloorFloatToInt32(u-0.5f);
2997 	int		x1						= x0+1;
2998 	int		y0						= deFloorFloatToInt32(v-0.5f);
2999 	int		y1						= y0+1;
3000 	IVec2	baseSampleCoords[4]		=
3001 	{
3002 		IVec2(x0, y0),
3003 		IVec2(x1, y0),
3004 		IVec2(x0, y1),
3005 		IVec2(x1, y1)
3006 	};
3007 	Vec4	sampleColors[4];
3008 	bool	hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
3009 
3010 	// Find correct faces and coordinates for out-of-bounds sample coordinates.
3011 
3012 	for (int i = 0; i < 4; i++)
3013 	{
3014 		CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
3015 		hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
3016 		if (!hasBothCoordsOutOfBounds[i])
3017 			sampleColors[i] = lookup(faceAccesses[coords.face], coords.s, coords.t, depth);
3018 	}
3019 
3020 	// If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
3021 	// \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
3022 	//		 requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
3023 	//		 must have this color as well.
3024 
3025 	{
3026 		int bothOutOfBoundsNdx = -1;
3027 		for (int i = 0; i < 4; i++)
3028 		{
3029 			if (hasBothCoordsOutOfBounds[i])
3030 			{
3031 				DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
3032 				bothOutOfBoundsNdx = i;
3033 			}
3034 		}
3035 		if (bothOutOfBoundsNdx != -1)
3036 		{
3037 			sampleColors[bothOutOfBoundsNdx] = Vec4(0.0f);
3038 			for (int i = 0; i < 4; i++)
3039 				if (i != bothOutOfBoundsNdx)
3040 					sampleColors[bothOutOfBoundsNdx] += sampleColors[i];
3041 
3042 			sampleColors[bothOutOfBoundsNdx] = sampleColors[bothOutOfBoundsNdx] * (1.0f/3.0f);
3043 		}
3044 	}
3045 
3046 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(sampleColors); i++)
3047 		dst[i] = sampleColors[i];
3048 }
3049 
3050 // \todo [2014-02-19 pyry] Optimize faceAccesses
sampleCubeSeamlessLinear(const ConstPixelBufferAccess (& faceAccesses)[CUBEFACE_LAST],CubeFace baseFace,const Sampler & sampler,float s,float t,int depth)3051 static Vec4 sampleCubeSeamlessLinear (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float s, float t, int depth)
3052 {
3053 	DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
3054 
3055 	int		size	= faceAccesses[0].getWidth();
3056 	// Non-normalized coordinates.
3057 	float	u		= s;
3058 	float	v		= t;
3059 
3060 	if (sampler.normalizedCoords)
3061 	{
3062 		u = unnormalize(sampler.wrapS, s, size);
3063 		v = unnormalize(sampler.wrapT, t, size);
3064 	}
3065 
3066 	// Get sample colors.
3067 
3068 	Vec4 sampleColors[4];
3069 	getCubeLinearSamples(faceAccesses, baseFace, u, v, depth, sampleColors);
3070 
3071 	// Interpolate.
3072 
3073 	float a = deFloatFrac(u-0.5f);
3074 	float b = deFloatFrac(v-0.5f);
3075 
3076 	return (sampleColors[0]*(1.0f-a)*(1.0f-b)) +
3077 		   (sampleColors[1]*(     a)*(1.0f-b)) +
3078 		   (sampleColors[2]*(1.0f-a)*(     b)) +
3079 		   (sampleColors[3]*(     a)*(     b));
3080 }
3081 
sampleLevelArrayCubeSeamless(const ConstPixelBufferAccess * const (& faces)[CUBEFACE_LAST],int numLevels,CubeFace face,const Sampler & sampler,float s,float t,int depth,float lod,ImageViewMinLodParams * minLodParams)3082 static Vec4 sampleLevelArrayCubeSeamless (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float s, float t, int depth, float lod, ImageViewMinLodParams* minLodParams)
3083 {
3084 	// minLodRelative is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
3085 	// The value is relative to baseLevel as the Texture*View was created as the baseLevel being level[0].
3086 	const float				minLodRelative	= (minLodParams != DE_NULL) ? getImageViewMinLod(minLodParams->minLod) - (float)minLodParams->baseLevel : 0.0f;
3087 	bool					magnified	= lod <= sampler.lodThreshold;
3088 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
3089 
3090 	// VK_EXT_image_view_min_lod: Integer Texel Coordinates case (with robustness2 supported)
3091 	if (minLodParams != DE_NULL && minLodParams->intTexCoord)
3092 	{
3093 		if (lod < deFloatFloor(minLodRelative) || lod >= (float)(numLevels - 1))
3094 			return Vec4(0.0f);
3095 
3096 		if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
3097 			return Vec4(0.0f);
3098 	}
3099 
3100 	switch (filterMode)
3101 	{
3102 		case Sampler::NEAREST:
3103 		{
3104 			bool isLinearMipmapMode	= magnified && tcu::isSamplerMipmapModeLinear(sampler.minFilter);
3105 			const int maxLevel		= (int)numLevels - 1;
3106 			const int level0		= isLinearMipmapMode ? (int)deFloatFloor(minLodRelative) : deClamp32((int)deFloatCeil(minLodRelative + 0.5f) - 1, 0, maxLevel);
3107 			tcu::Vec4 t0			= sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
3108 
3109 			if (!isLinearMipmapMode)
3110 				return t0;
3111 
3112 			const float frac		= deFloatFrac(minLodRelative);
3113 			const int level1		= de::min(level0 + 1, maxLevel);
3114 			tcu::Vec4 t1			= sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
3115 			return t0*(1.0f - frac) + t1*frac;
3116 		}
3117 
3118 		case Sampler::LINEAR:
3119 		{
3120 			bool cond = sampler.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || sampler.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
3121 			const int index = cond ? (int)deFloatFloor(minLodRelative) : ((int)deFloatCeil(minLodRelative + 0.5f) - 1u);
3122 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3123 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3124 				faceAccesses[i] = faces[i][index];
3125 
3126 			Vec4 result = sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
3127 
3128 
3129 			if (cond && ((index + 1) < numLevels) && deFloatFrac(minLodRelative) != 0.0f)
3130 			{
3131 				// In case of a minLodRelative value with fractional part, we need to ponderate the different sample of N level
3132 				// and sample for level N+1 accordingly.
3133 				result = result * (1.0f - deFloatFrac(minLodRelative));
3134 
3135 				ConstPixelBufferAccess faceAccessesNext[CUBEFACE_LAST];
3136 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3137 					faceAccessesNext[i] = faces[i][index + 1];
3138 				result += sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth) * deFloatFrac(minLodRelative);
3139 			}
3140 			return result;
3141 		}
3142 
3143 		case Sampler::NEAREST_MIPMAP_NEAREST:
3144 		case Sampler::LINEAR_MIPMAP_NEAREST:
3145 		{
3146 			if (minLodParams != DE_NULL && !minLodParams->intTexCoord)
3147 				lod = de::max(lod, minLodRelative);
3148 
3149 			int						maxLevel	= (int)numLevels-1;
3150 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3151 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3152 
3153 			if (levelFilter == Sampler::NEAREST)
3154 				return sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
3155 			else
3156 			{
3157 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3158 
3159 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3160 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3161 					faceAccesses[i] = faces[i][level];
3162 
3163 				return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
3164 			}
3165 		}
3166 
3167 		case Sampler::NEAREST_MIPMAP_LINEAR:
3168 		case Sampler::LINEAR_MIPMAP_LINEAR:
3169 		{
3170 			if (minLodParams != DE_NULL && !minLodParams->intTexCoord)
3171 				lod = de::max(lod, minLodRelative);
3172 
3173 			int						maxLevel	= (int)numLevels-1;
3174 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3175 			int						level1		= de::min(maxLevel, level0 + 1);
3176 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3177 			float					f			= deFloatFrac(lod);
3178 			Vec4					t0;
3179 			Vec4					t1;
3180 
3181 			if (levelFilter == Sampler::NEAREST)
3182 			{
3183 				t0 = sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
3184 				t1 = sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
3185 			}
3186 			else
3187 			{
3188 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3189 
3190 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3191 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3192 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3193 				{
3194 					faceAccesses0[i] = faces[i][level0];
3195 					faceAccesses1[i] = faces[i][level1];
3196 				}
3197 
3198 				t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
3199 				t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
3200 			}
3201 
3202 			return t0*(1.0f - f) + t1*f;
3203 		}
3204 
3205 		default:
3206 			DE_ASSERT(DE_FALSE);
3207 			return Vec4(0.0f);
3208 	}
3209 }
3210 
sampleCubeSeamlessNearestCompare(const ConstPixelBufferAccess & faceAccess,const Sampler & sampler,float ref,float s,float t,int depth=0)3211 static float sampleCubeSeamlessNearestCompare (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float ref, float s, float t, int depth = 0)
3212 {
3213 	Sampler clampingSampler = sampler;
3214 	clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
3215 	clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
3216 	return faceAccess.sample2DCompare(clampingSampler, Sampler::NEAREST, ref, s, t, IVec3(0, 0, depth));
3217 }
3218 
sampleCubeSeamlessLinearCompare(const ConstPixelBufferAccess (& faceAccesses)[CUBEFACE_LAST],CubeFace baseFace,const Sampler & sampler,float ref,float s,float t)3219 static float sampleCubeSeamlessLinearCompare (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float ref, float s, float t)
3220 {
3221 	DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
3222 
3223 	int		size	= faceAccesses[0].getWidth();
3224 	// Non-normalized coordinates.
3225 	float	u		= s;
3226 	float	v		= t;
3227 
3228 	if (sampler.normalizedCoords)
3229 	{
3230 		u = unnormalize(sampler.wrapS, s, size);
3231 		v = unnormalize(sampler.wrapT, t, size);
3232 	}
3233 
3234 	int			x0						= deFloorFloatToInt32(u-0.5f);
3235 	int			x1						= x0+1;
3236 	int			y0						= deFloorFloatToInt32(v-0.5f);
3237 	int			y1						= y0+1;
3238 	IVec2		baseSampleCoords[4]		=
3239 	{
3240 		IVec2(x0, y0),
3241 		IVec2(x1, y0),
3242 		IVec2(x0, y1),
3243 		IVec2(x1, y1)
3244 	};
3245 	float		sampleRes[4];
3246 	bool		hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
3247 
3248 	// Find correct faces and coordinates for out-of-bounds sample coordinates.
3249 
3250 	for (int i = 0; i < 4; i++)
3251 	{
3252 		CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
3253 		hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
3254 
3255 		if (!hasBothCoordsOutOfBounds[i])
3256 		{
3257 			const bool isFixedPointDepth = isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
3258 
3259 			sampleRes[i] = execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
3260 		}
3261 	}
3262 
3263 	// If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
3264 	// \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
3265 	//		 requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
3266 	//		 must have this color as well.
3267 
3268 	{
3269 		int bothOutOfBoundsNdx = -1;
3270 		for (int i = 0; i < 4; i++)
3271 		{
3272 			if (hasBothCoordsOutOfBounds[i])
3273 			{
3274 				DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
3275 				bothOutOfBoundsNdx = i;
3276 			}
3277 		}
3278 		if (bothOutOfBoundsNdx != -1)
3279 		{
3280 			sampleRes[bothOutOfBoundsNdx] = 0.0f;
3281 			for (int i = 0; i < 4; i++)
3282 				if (i != bothOutOfBoundsNdx)
3283 					sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
3284 
3285 			sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0f/3.0f);
3286 		}
3287 	}
3288 
3289 	// Interpolate.
3290 
3291 	float a = deFloatFrac(u-0.5f);
3292 	float b = deFloatFrac(v-0.5f);
3293 
3294 	return (sampleRes[0]*(1.0f-a)*(1.0f-b)) +
3295 		   (sampleRes[1]*(     a)*(1.0f-b)) +
3296 		   (sampleRes[2]*(1.0f-a)*(     b)) +
3297 		   (sampleRes[3]*(     a)*(     b));
3298 }
3299 
sampleLevelArrayCubeSeamlessCompare(const ConstPixelBufferAccess * const (& faces)[CUBEFACE_LAST],int numLevels,CubeFace face,const Sampler & sampler,float ref,float s,float t,float lod)3300 static float sampleLevelArrayCubeSeamlessCompare (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
3301 {
3302 	bool					magnified	= lod <= sampler.lodThreshold;
3303 	Sampler::FilterMode		filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
3304 
3305 	switch (filterMode)
3306 	{
3307 		case Sampler::NEAREST:
3308 			return sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
3309 
3310 		case Sampler::LINEAR:
3311 		{
3312 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3313 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3314 				faceAccesses[i] = faces[i][0];
3315 
3316 			return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3317 		}
3318 
3319 		case Sampler::NEAREST_MIPMAP_NEAREST:
3320 		case Sampler::LINEAR_MIPMAP_NEAREST:
3321 		{
3322 			int						maxLevel	= (int)numLevels-1;
3323 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3324 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3325 
3326 			if (levelFilter == Sampler::NEAREST)
3327 				return sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
3328 			else
3329 			{
3330 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3331 
3332 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3333 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3334 					faceAccesses[i] = faces[i][level];
3335 
3336 				return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3337 			}
3338 		}
3339 
3340 		case Sampler::NEAREST_MIPMAP_LINEAR:
3341 		case Sampler::LINEAR_MIPMAP_LINEAR:
3342 		{
3343 			int						maxLevel	= (int)numLevels-1;
3344 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3345 			int						level1		= de::min(maxLevel, level0 + 1);
3346 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3347 			float					f			= deFloatFrac(lod);
3348 			float					t0;
3349 			float					t1;
3350 
3351 			if (levelFilter == Sampler::NEAREST)
3352 			{
3353 				t0 = sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
3354 				t1 = sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
3355 			}
3356 			else
3357 			{
3358 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3359 
3360 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3361 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3362 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3363 				{
3364 					faceAccesses0[i] = faces[i][level0];
3365 					faceAccesses1[i] = faces[i][level1];
3366 				}
3367 
3368 				t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
3369 				t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
3370 			}
3371 
3372 			return t0*(1.0f - f) + t1*f;
3373 		}
3374 
3375 		default:
3376 			DE_ASSERT(DE_FALSE);
3377 			return 0.0f;
3378 	}
3379 }
3380 
3381 // Cube map array sampling
3382 
getCubeArrayFaceAccess(const ConstPixelBufferAccess * const levels,int levelNdx,int slice,CubeFace face)3383 static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face)
3384 {
3385 	const ConstPixelBufferAccess&	level	= levels[levelNdx];
3386 	const int						depth	= (slice * 6) + getCubeArrayFaceIndex(face);
3387 
3388 	return getSubregion(level, 0, 0, depth, level.getWidth(), level.getHeight(), 1);
3389 }
3390 
sampleCubeArraySeamless(const ConstPixelBufferAccess * const levels,int numLevels,int slice,CubeFace face,const Sampler & sampler,float s,float t,float lod)3391 static Vec4 sampleCubeArraySeamless (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float s, float t, float lod)
3392 {
3393 	const int					faceDepth	= (slice * 6) + getCubeArrayFaceIndex(face);
3394 	const bool					magnified	= lod <= sampler.lodThreshold;
3395 	const Sampler::FilterMode	filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
3396 
3397 	switch (filterMode)
3398 	{
3399 		case Sampler::NEAREST:
3400 			return sampleCubeSeamlessNearest(levels[0], sampler, s, t, faceDepth);
3401 
3402 		case Sampler::LINEAR:
3403 		{
3404 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3405 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3406 				faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
3407 
3408 			return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
3409 		}
3410 
3411 		case Sampler::NEAREST_MIPMAP_NEAREST:
3412 		case Sampler::LINEAR_MIPMAP_NEAREST:
3413 		{
3414 			int						maxLevel	= (int)numLevels-1;
3415 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3416 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3417 
3418 			if (levelFilter == Sampler::NEAREST)
3419 				return sampleCubeSeamlessNearest(levels[level], sampler, s, t, faceDepth);
3420 			else
3421 			{
3422 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3423 
3424 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3425 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3426 					faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
3427 
3428 				return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
3429 			}
3430 		}
3431 
3432 		case Sampler::NEAREST_MIPMAP_LINEAR:
3433 		case Sampler::LINEAR_MIPMAP_LINEAR:
3434 		{
3435 			int						maxLevel	= (int)numLevels-1;
3436 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3437 			int						level1		= de::min(maxLevel, level0 + 1);
3438 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3439 			float					f			= deFloatFrac(lod);
3440 			Vec4					t0;
3441 			Vec4					t1;
3442 
3443 			if (levelFilter == Sampler::NEAREST)
3444 			{
3445 				t0 = sampleCubeSeamlessNearest(levels[level0], sampler, s, t, faceDepth);
3446 				t1 = sampleCubeSeamlessNearest(levels[level1], sampler, s, t, faceDepth);
3447 			}
3448 			else
3449 			{
3450 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3451 
3452 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3453 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3454 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3455 				{
3456 					faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
3457 					faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
3458 				}
3459 
3460 				t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, 0);
3461 				t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, 0);
3462 			}
3463 
3464 			return t0*(1.0f - f) + t1*f;
3465 		}
3466 
3467 		default:
3468 			DE_ASSERT(DE_FALSE);
3469 			return Vec4(0.0f);
3470 	}
3471 }
3472 
sampleCubeArraySeamlessCompare(const ConstPixelBufferAccess * const levels,int numLevels,int slice,CubeFace face,const Sampler & sampler,float ref,float s,float t,float lod)3473 static float sampleCubeArraySeamlessCompare (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
3474 {
3475 	const int			faceDepth	= (slice * 6) + getCubeArrayFaceIndex(face);
3476 	const bool			magnified	= lod <= sampler.lodThreshold;
3477 	Sampler::FilterMode	filterMode	= magnified ? sampler.magFilter : sampler.minFilter;
3478 
3479 	switch (filterMode)
3480 	{
3481 		case Sampler::NEAREST:
3482 			return sampleCubeSeamlessNearestCompare(levels[0], sampler, ref, s, t, faceDepth);
3483 
3484 		case Sampler::LINEAR:
3485 		{
3486 			ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3487 			for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3488 				faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
3489 
3490 			return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3491 		}
3492 
3493 		case Sampler::NEAREST_MIPMAP_NEAREST:
3494 		case Sampler::LINEAR_MIPMAP_NEAREST:
3495 		{
3496 			int						maxLevel	= (int)numLevels-1;
3497 			int						level		= deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3498 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3499 
3500 			if (levelFilter == Sampler::NEAREST)
3501 				return sampleCubeSeamlessNearestCompare(levels[level], sampler, ref, s, t, faceDepth);
3502 			else
3503 			{
3504 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3505 
3506 				ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3507 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3508 					faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
3509 
3510 				return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3511 			}
3512 		}
3513 
3514 		case Sampler::NEAREST_MIPMAP_LINEAR:
3515 		case Sampler::LINEAR_MIPMAP_LINEAR:
3516 		{
3517 			int						maxLevel	= (int)numLevels-1;
3518 			int						level0		= deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3519 			int						level1		= de::min(maxLevel, level0 + 1);
3520 			Sampler::FilterMode		levelFilter	= (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3521 			float					f			= deFloatFrac(lod);
3522 			float					t0;
3523 			float					t1;
3524 
3525 			if (levelFilter == Sampler::NEAREST)
3526 			{
3527 				t0 = sampleCubeSeamlessNearestCompare(levels[level0], sampler, ref, s, t, faceDepth);
3528 				t1 = sampleCubeSeamlessNearestCompare(levels[level1], sampler, ref, s, t, faceDepth);
3529 			}
3530 			else
3531 			{
3532 				DE_ASSERT(levelFilter == Sampler::LINEAR);
3533 
3534 				ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3535 				ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3536 				for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3537 				{
3538 					faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
3539 					faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
3540 				}
3541 
3542 				t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
3543 				t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
3544 			}
3545 
3546 			return t0*(1.0f - f) + t1*f;
3547 		}
3548 
3549 		default:
3550 			DE_ASSERT(DE_FALSE);
3551 			return 0.0f;
3552 	}
3553 }
3554 
computeMipPyramidLevels(int size)3555 inline int computeMipPyramidLevels (int size)
3556 {
3557 	return deLog2Floor32(size)+1;
3558 }
3559 
computeMipPyramidLevels(int width,int height)3560 inline int computeMipPyramidLevels (int width, int height)
3561 {
3562 	return deLog2Floor32(de::max(width, height))+1;
3563 }
3564 
computeMipPyramidLevels(int width,int height,int depth)3565 inline int computeMipPyramidLevels (int width, int height, int depth)
3566 {
3567 	return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
3568 }
3569 
getMipPyramidLevelSize(int baseLevelSize,int levelNdx)3570 inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx)
3571 {
3572 	return de::max(baseLevelSize >> levelNdx, 1);
3573 }
3574 
3575 // TextureLevelPyramid
3576 
TextureLevelPyramid(const TextureFormat & format,int numLevels)3577 TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels)
3578 	: m_format	(format)
3579 	, m_data	(numLevels)
3580 	, m_access	(numLevels)
3581 {
3582 }
3583 
TextureLevelPyramid(const TextureLevelPyramid & other)3584 TextureLevelPyramid::TextureLevelPyramid (const TextureLevelPyramid& other)
3585 	: m_format	(other.m_format)
3586 	, m_data	(other.getNumLevels())
3587 	, m_access	(other.getNumLevels())
3588 {
3589 	for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3590 	{
3591 		if (!other.isLevelEmpty(levelNdx))
3592 		{
3593 			const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
3594 
3595 			m_data[levelNdx] = other.m_data[levelNdx];
3596 			m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
3597 		}
3598 	}
3599 }
3600 
operator =(const TextureLevelPyramid & other)3601 TextureLevelPyramid& TextureLevelPyramid::operator= (const TextureLevelPyramid& other)
3602 {
3603 	if (this == &other)
3604 		return *this;
3605 
3606 	m_format = other.m_format;
3607 	m_data.resize(other.getNumLevels());
3608 	m_access.resize(other.getNumLevels());
3609 
3610 	for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3611 	{
3612 		if (!other.isLevelEmpty(levelNdx))
3613 		{
3614 			const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
3615 
3616 			m_data[levelNdx] = other.m_data[levelNdx];
3617 			m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
3618 		}
3619 		else if (!isLevelEmpty(levelNdx))
3620 			clearLevel(levelNdx);
3621 	}
3622 
3623 	return *this;
3624 }
3625 
~TextureLevelPyramid(void)3626 TextureLevelPyramid::~TextureLevelPyramid (void)
3627 {
3628 }
3629 
allocLevel(int levelNdx,int width,int height,int depth)3630 void TextureLevelPyramid::allocLevel (int levelNdx, int width, int height, int depth)
3631 {
3632 	const int	size	= m_format.getPixelSize()*width*height*depth;
3633 
3634 	DE_ASSERT(isLevelEmpty(levelNdx));
3635 
3636 	m_data[levelNdx].setStorage(size);
3637 	m_access[levelNdx] = PixelBufferAccess(m_format, width, height, depth, m_data[levelNdx].getPtr());
3638 }
3639 
clearLevel(int levelNdx)3640 void TextureLevelPyramid::clearLevel (int levelNdx)
3641 {
3642 	DE_ASSERT(!isLevelEmpty(levelNdx));
3643 
3644 	m_data[levelNdx].clear();
3645 	m_access[levelNdx] = PixelBufferAccess();
3646 }
3647 
3648 // Texture1D
3649 
Texture1D(const TextureFormat & format,int width)3650 Texture1D::Texture1D (const TextureFormat& format, int width)
3651 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width))
3652 	, m_width				(width)
3653 	, m_view				(getNumLevels(), getLevels())
3654 {
3655 }
3656 
Texture1D(const Texture1D & other)3657 Texture1D::Texture1D (const Texture1D& other)
3658 	: TextureLevelPyramid	(other)
3659 	, m_width				(other.m_width)
3660 	, m_view				(getNumLevels(), getLevels())
3661 {
3662 }
3663 
operator =(const Texture1D & other)3664 Texture1D& Texture1D::operator= (const Texture1D& other)
3665 {
3666 	if (this == &other)
3667 		return *this;
3668 
3669 	TextureLevelPyramid::operator=(other);
3670 
3671 	m_width		= other.m_width;
3672 	m_view		= Texture1DView(getNumLevels(), getLevels());
3673 
3674 	return *this;
3675 }
3676 
~Texture1D(void)3677 Texture1D::~Texture1D (void)
3678 {
3679 }
3680 
allocLevel(int levelNdx)3681 void Texture1D::allocLevel (int levelNdx)
3682 {
3683 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3684 
3685 	const int width = getMipPyramidLevelSize(m_width, levelNdx);
3686 
3687 	TextureLevelPyramid::allocLevel(levelNdx, width, 1, 1);
3688 }
3689 
3690 // Texture2D
3691 
Texture2D(const TextureFormat & format,int width,int height,bool es2)3692 Texture2D::Texture2D (const TextureFormat& format, int width, int height, bool es2)
3693 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width, height))
3694 	, m_yuvTextureUsed	(false)
3695 	, m_width		(width)
3696 	, m_height		(height)
3697 	, m_view		(getNumLevels(), getLevels(), es2)
3698 {
3699 }
3700 
Texture2D(const TextureFormat & format,int width,int height,int mipmaps)3701 Texture2D::Texture2D (const TextureFormat& format, int width, int height, int mipmaps)
3702 	: TextureLevelPyramid	(format, mipmaps)
3703 	, m_yuvTextureUsed	(false)
3704 	, m_width		(width)
3705 	, m_height		(height)
3706 	, m_view		(getNumLevels(), getLevels())
3707 {
3708 }
3709 
Texture2D(const Texture2D & other)3710 Texture2D::Texture2D (const Texture2D& other)
3711 	: TextureLevelPyramid	(other)
3712 	, m_yuvTextureUsed	(other.m_yuvTextureUsed)
3713 	, m_width		(other.m_width)
3714 	, m_height		(other.m_height)
3715 	, m_view		(getNumLevels(), getLevels(), other.getView().isES2())
3716 {
3717 }
3718 
operator =(const Texture2D & other)3719 Texture2D& Texture2D::operator= (const Texture2D& other)
3720 {
3721 	if (this == &other)
3722 		return *this;
3723 
3724 	TextureLevelPyramid::operator=(other);
3725 
3726 	m_width		= other.m_width;
3727 	m_height	= other.m_height;
3728 	m_view		= Texture2DView(getNumLevels(), getLevels(), other.getView().isES2());
3729 	m_yuvTextureUsed = other.m_yuvTextureUsed;
3730 	return *this;
3731 }
3732 
~Texture2D(void)3733 Texture2D::~Texture2D (void)
3734 {
3735 }
3736 
allocLevel(int levelNdx)3737 void Texture2D::allocLevel (int levelNdx)
3738 {
3739 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3740 
3741 	const int	width	= getMipPyramidLevelSize(m_width, levelNdx);
3742 	const int	height	= getMipPyramidLevelSize(m_height, levelNdx);
3743 
3744 	TextureLevelPyramid::allocLevel(levelNdx, width, height, 1);
3745 }
3746 
3747 // TextureCubeView
3748 
TextureCubeView(void)3749 TextureCubeView::TextureCubeView (void)
3750 	: m_numLevels(0)
3751 	, m_es2(false)
3752 	, m_minLodParams (DE_NULL)
3753 {
3754 	for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3755 		m_levels[ndx] = DE_NULL;
3756 }
3757 
TextureCubeView(int numLevels,const ConstPixelBufferAccess * const (& levels)[CUBEFACE_LAST],bool es2,ImageViewMinLodParams * minLodParams)3758 TextureCubeView::TextureCubeView (int numLevels, const ConstPixelBufferAccess* const (&levels) [CUBEFACE_LAST], bool es2, ImageViewMinLodParams *minLodParams)
3759 	: m_numLevels(numLevels)
3760 	, m_es2(es2)
3761 	, m_minLodParams(minLodParams)
3762 {
3763 	for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3764 		m_levels[ndx] = levels[ndx];
3765 }
3766 
sample(const Sampler & sampler,float s,float t,float r,float lod) const3767 tcu::Vec4 TextureCubeView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3768 {
3769 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3770 
3771 	// Computes (face, s, t).
3772 	const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3773 	if (sampler.seamlessCubeMap)
3774 		return sampleLevelArrayCubeSeamless(m_levels, m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod, m_minLodParams);
3775 	else
3776 		return sampleLevelArray2D(m_levels[coords.face], m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod, m_es2, m_minLodParams);
3777 }
3778 
sampleCompare(const Sampler & sampler,float ref,float s,float t,float r,float lod) const3779 float TextureCubeView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3780 {
3781 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3782 
3783 	// Computes (face, s, t).
3784 	const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3785 	if (sampler.seamlessCubeMap)
3786 		return sampleLevelArrayCubeSeamlessCompare(m_levels, m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod);
3787 	else
3788 		return sampleLevelArray2DCompare(m_levels[coords.face], m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, 0));
3789 }
3790 
gather(const Sampler & sampler,float s,float t,float r,int componentNdx) const3791 Vec4 TextureCubeView::gather (const Sampler& sampler, float s, float t, float r, int componentNdx) const
3792 {
3793 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3794 
3795 	ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3796 	for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3797 		faceAccesses[i] = m_levels[i][0];
3798 
3799 	const CubeFaceFloatCoords	coords	= getCubeFaceCoords(Vec3(s, t, r));
3800 	const int					size	= faceAccesses[0].getWidth();
3801 	// Non-normalized coordinates.
3802 	float						u		= coords.s;
3803 	float						v		= coords.t;
3804 
3805 	if (sampler.normalizedCoords)
3806 	{
3807 		u = unnormalize(sampler.wrapS, coords.s, size);
3808 		v = unnormalize(sampler.wrapT, coords.t, size);
3809 	}
3810 
3811 	Vec4 sampleColors[4];
3812 	getCubeLinearSamples(faceAccesses, coords.face, u, v, 0, sampleColors);
3813 
3814 	const int	sampleIndices[4] = { 2, 3, 1, 0 }; // \note Gather returns the samples in a non-obvious order.
3815 	Vec4		result;
3816 	for (int i = 0; i < 4; i++)
3817 		result[i] = sampleColors[sampleIndices[i]][componentNdx];
3818 
3819 	return result;
3820 }
3821 
gatherCompare(const Sampler & sampler,float ref,float s,float t,float r) const3822 Vec4 TextureCubeView::gatherCompare (const Sampler& sampler, float ref, float s, float t, float r) const
3823 {
3824 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3825 	DE_ASSERT(m_levels[0][0].getFormat().order == TextureFormat::D || m_levels[0][0].getFormat().order == TextureFormat::DS);
3826 	DE_ASSERT(sampler.compareChannel == 0);
3827 
3828 	Sampler noCompareSampler = sampler;
3829 	noCompareSampler.compare = Sampler::COMPAREMODE_NONE;
3830 
3831 	const Vec4 gathered			= gather(noCompareSampler, s, t, r, 0 /* component 0: depth */);
3832 	const bool isFixedPoint		= isFixedPointDepthTextureFormat(m_levels[0][0].getFormat());
3833 	Vec4 result;
3834 	for (int i = 0; i < 4; i++)
3835 		result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
3836 
3837 	return result;
3838 }
3839 
3840 // TextureCube
3841 
TextureCube(const TextureFormat & format,int size,bool es2)3842 TextureCube::TextureCube (const TextureFormat& format, int size, bool es2)
3843 	: m_format	(format)
3844 	, m_size	(size)
3845 {
3846 	const int						numLevels		= computeMipPyramidLevels(m_size);
3847 	const ConstPixelBufferAccess*	levels[CUBEFACE_LAST];
3848 
3849 	for (int face = 0; face < CUBEFACE_LAST; face++)
3850 	{
3851 		m_data[face].resize(numLevels);
3852 		m_access[face].resize(numLevels);
3853 		levels[face] = &m_access[face][0];
3854 	}
3855 
3856 	m_view = TextureCubeView(numLevels, levels, es2);
3857 }
3858 
TextureCube(const TextureCube & other)3859 TextureCube::TextureCube (const TextureCube& other)
3860 	: m_format	(other.m_format)
3861 	, m_size	(other.m_size)
3862 {
3863 	const int						numLevels		= computeMipPyramidLevels(m_size);
3864 	const ConstPixelBufferAccess*	levels[CUBEFACE_LAST];
3865 
3866 	for (int face = 0; face < CUBEFACE_LAST; face++)
3867 	{
3868 		m_data[face].resize(numLevels);
3869 		m_access[face].resize(numLevels);
3870 		levels[face] = &m_access[face][0];
3871 	}
3872 
3873 	m_view = TextureCubeView(numLevels, levels, other.getView().isES2());
3874 
3875 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3876 	{
3877 		for (int face = 0; face < CUBEFACE_LAST; face++)
3878 		{
3879 			if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3880 			{
3881 				allocLevel((CubeFace)face, levelNdx);
3882 				copy(getLevelFace(levelNdx, (CubeFace)face),
3883 					 other.getLevelFace(levelNdx, (CubeFace)face));
3884 			}
3885 		}
3886 	}
3887 }
3888 
operator =(const TextureCube & other)3889 TextureCube& TextureCube::operator= (const TextureCube& other)
3890 {
3891 	if (this == &other)
3892 		return *this;
3893 
3894 	const int						numLevels		= computeMipPyramidLevels(other.m_size);
3895 	const ConstPixelBufferAccess*	levels[CUBEFACE_LAST];
3896 
3897 	for (int face = 0; face < CUBEFACE_LAST; face++)
3898 	{
3899 		m_data[face].resize(numLevels);
3900 		m_access[face].resize(numLevels);
3901 		levels[face] = &m_access[face][0];
3902 	}
3903 
3904 	m_format	= other.m_format;
3905 	m_size		= other.m_size;
3906 	m_view		= TextureCubeView(numLevels, levels, other.getView().isES2());
3907 
3908 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3909 	{
3910 		for (int face = 0; face < CUBEFACE_LAST; face++)
3911 		{
3912 			if (!isLevelEmpty((CubeFace)face, levelNdx))
3913 				clearLevel((CubeFace)face, levelNdx);
3914 
3915 			if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3916 			{
3917 				allocLevel((CubeFace)face, levelNdx);
3918 				copy(getLevelFace(levelNdx, (CubeFace)face),
3919 					 other.getLevelFace(levelNdx, (CubeFace)face));
3920 			}
3921 		}
3922 	}
3923 
3924 	return *this;
3925 }
3926 
~TextureCube(void)3927 TextureCube::~TextureCube (void)
3928 {
3929 }
3930 
allocLevel(tcu::CubeFace face,int levelNdx)3931 void TextureCube::allocLevel (tcu::CubeFace face, int levelNdx)
3932 {
3933 	const int	size		= getMipPyramidLevelSize(m_size, levelNdx);
3934 	const int	dataSize	= m_format.getPixelSize()*size*size;
3935 	DE_ASSERT(isLevelEmpty(face, levelNdx));
3936 
3937 	m_data[face][levelNdx].setStorage(dataSize);
3938 	m_access[face][levelNdx] = PixelBufferAccess(m_format, size, size, 1, m_data[face][levelNdx].getPtr());
3939 }
3940 
clearLevel(tcu::CubeFace face,int levelNdx)3941 void TextureCube::clearLevel (tcu::CubeFace face, int levelNdx)
3942 {
3943 	DE_ASSERT(!isLevelEmpty(face, levelNdx));
3944 	m_data[face][levelNdx].clear();
3945 	m_access[face][levelNdx] = PixelBufferAccess();
3946 }
3947 
3948 // Texture1DArrayView
3949 
Texture1DArrayView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR,ImageViewMinLodParams * minLodParams DE_UNUSED_ATTR)3950 Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR, ImageViewMinLodParams* minLodParams DE_UNUSED_ATTR)
3951 	: m_numLevels	(numLevels)
3952 	, m_levels		(levels)
3953 {
3954 }
3955 
selectLayer(float t) const3956 inline int Texture1DArrayView::selectLayer (float t) const
3957 {
3958 	DE_ASSERT(m_numLevels > 0 && m_levels);
3959 	return de::clamp(deFloorFloatToInt32(t + 0.5f), 0, m_levels[0].getHeight()-1);
3960 }
3961 
sample(const Sampler & sampler,float s,float t,float lod) const3962 Vec4 Texture1DArrayView::sample (const Sampler& sampler, float s, float t, float lod) const
3963 {
3964 	return sampleLevelArray1D(m_levels, m_numLevels, sampler, s, selectLayer(t), lod);
3965 }
3966 
sampleOffset(const Sampler & sampler,float s,float t,float lod,deInt32 offset) const3967 Vec4 Texture1DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float lod, deInt32 offset) const
3968 {
3969 	return sampleLevelArray1DOffset(m_levels, m_numLevels, sampler, s, lod, IVec2(offset, selectLayer(t)));
3970 }
3971 
sampleCompare(const Sampler & sampler,float ref,float s,float t,float lod) const3972 float Texture1DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float lod) const
3973 {
3974 	return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(0, selectLayer(t)));
3975 }
3976 
sampleCompareOffset(const Sampler & sampler,float ref,float s,float t,float lod,deInt32 offset) const3977 float Texture1DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float lod, deInt32 offset) const
3978 {
3979 	return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(offset, selectLayer(t)));
3980 }
3981 
3982 // Texture2DArrayView
3983 
Texture2DArrayView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR,ImageViewMinLodParams * minLodParams DE_UNUSED_ATTR)3984 Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR, ImageViewMinLodParams* minLodParams DE_UNUSED_ATTR)
3985 	: m_numLevels	(numLevels)
3986 	, m_levels		(levels)
3987 {
3988 }
3989 
selectLayer(float r) const3990 inline int Texture2DArrayView::selectLayer (float r) const
3991 {
3992 	DE_ASSERT(m_numLevels > 0 && m_levels);
3993 	return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getDepth()-1);
3994 }
3995 
sample(const Sampler & sampler,float s,float t,float r,float lod) const3996 Vec4 Texture2DArrayView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3997 {
3998 	return sampleLevelArray2D(m_levels, m_numLevels, sampler, s, t, selectLayer(r), lod);
3999 }
4000 
sampleCompare(const Sampler & sampler,float ref,float s,float t,float r,float lod) const4001 float Texture2DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
4002 {
4003 	return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(0, 0, selectLayer(r)));
4004 }
4005 
sampleOffset(const Sampler & sampler,float s,float t,float r,float lod,const IVec2 & offset) const4006 Vec4 Texture2DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float r, float lod, const IVec2& offset) const
4007 {
4008 	return sampleLevelArray2DOffset(m_levels, m_numLevels, sampler, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
4009 }
4010 
sampleCompareOffset(const Sampler & sampler,float ref,float s,float t,float r,float lod,const IVec2 & offset) const4011 float Texture2DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float r, float lod, const IVec2& offset) const
4012 {
4013 	return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
4014 }
4015 
gatherOffsets(const Sampler & sampler,float s,float t,float r,int componentNdx,const IVec2 (& offsets)[4]) const4016 Vec4 Texture2DArrayView::gatherOffsets (const Sampler& sampler, float s, float t, float r, int componentNdx, const IVec2 (&offsets)[4]) const
4017 {
4018 	return gatherArray2DOffsets(m_levels[0], sampler, s, t, selectLayer(r), componentNdx, offsets);
4019 }
4020 
gatherOffsetsCompare(const Sampler & sampler,float ref,float s,float t,float r,const IVec2 (& offsets)[4]) const4021 Vec4 Texture2DArrayView::gatherOffsetsCompare (const Sampler& sampler, float ref, float s, float t, float r, const IVec2 (&offsets)[4]) const
4022 {
4023 	return gatherArray2DOffsetsCompare(m_levels[0], sampler, ref, s, t, selectLayer(r), offsets);
4024 }
4025 
4026 // Texture1DArray
4027 
Texture1DArray(const TextureFormat & format,int width,int numLayers)4028 Texture1DArray::Texture1DArray (const TextureFormat& format, int width, int numLayers)
4029 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width))
4030 	, m_width				(width)
4031 	, m_numLayers			(numLayers)
4032 	, m_view				(getNumLevels(), getLevels())
4033 {
4034 }
4035 
Texture1DArray(const Texture1DArray & other)4036 Texture1DArray::Texture1DArray (const Texture1DArray& other)
4037 	: TextureLevelPyramid	(other)
4038 	, m_width				(other.m_width)
4039 	, m_numLayers			(other.m_numLayers)
4040 	, m_view				(getNumLevels(), getLevels())
4041 {
4042 }
4043 
operator =(const Texture1DArray & other)4044 Texture1DArray& Texture1DArray::operator= (const Texture1DArray& other)
4045 {
4046 	if (this == &other)
4047 		return *this;
4048 
4049 	TextureLevelPyramid::operator=(other);
4050 
4051 	m_width		= other.m_width;
4052 	m_numLayers	= other.m_numLayers;
4053 	m_view		= Texture1DArrayView(getNumLevels(), getLevels());
4054 
4055 	return *this;
4056 }
4057 
~Texture1DArray(void)4058 Texture1DArray::~Texture1DArray (void)
4059 {
4060 }
4061 
allocLevel(int levelNdx)4062 void Texture1DArray::allocLevel (int levelNdx)
4063 {
4064 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
4065 
4066 	const int width = getMipPyramidLevelSize(m_width, levelNdx);
4067 
4068 	TextureLevelPyramid::allocLevel(levelNdx, width, m_numLayers, 1);
4069 }
4070 
4071 // Texture2DArray
4072 
Texture2DArray(const TextureFormat & format,int width,int height,int numLayers)4073 Texture2DArray::Texture2DArray (const TextureFormat& format, int width, int height, int numLayers)
4074 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width, height))
4075 	, m_width				(width)
4076 	, m_height				(height)
4077 	, m_numLayers			(numLayers)
4078 	, m_view				(getNumLevels(), getLevels())
4079 {
4080 }
4081 
Texture2DArray(const Texture2DArray & other)4082 Texture2DArray::Texture2DArray (const Texture2DArray& other)
4083 	: TextureLevelPyramid	(other)
4084 	, m_width				(other.m_width)
4085 	, m_height				(other.m_height)
4086 	, m_numLayers			(other.m_numLayers)
4087 	, m_view				(getNumLevels(), getLevels())
4088 {
4089 }
4090 
operator =(const Texture2DArray & other)4091 Texture2DArray& Texture2DArray::operator= (const Texture2DArray& other)
4092 {
4093 	if (this == &other)
4094 		return *this;
4095 
4096 	TextureLevelPyramid::operator=(other);
4097 
4098 	m_width		= other.m_width;
4099 	m_height	= other.m_height;
4100 	m_numLayers	= other.m_numLayers;
4101 	m_view		= Texture2DArrayView(getNumLevels(), getLevels());
4102 
4103 	return *this;
4104 }
4105 
~Texture2DArray(void)4106 Texture2DArray::~Texture2DArray (void)
4107 {
4108 }
4109 
allocLevel(int levelNdx)4110 void Texture2DArray::allocLevel (int levelNdx)
4111 {
4112 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
4113 
4114 	const int	width	= getMipPyramidLevelSize(m_width,	levelNdx);
4115 	const int	height	= getMipPyramidLevelSize(m_height,	levelNdx);
4116 
4117 	TextureLevelPyramid::allocLevel(levelNdx, width, height, m_numLayers);
4118 }
4119 
4120 // Texture3DView
4121 
Texture3DView(int numLevels,const ConstPixelBufferAccess * levels,bool es2,ImageViewMinLodParams * minLodParams)4122 Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels, bool es2, ImageViewMinLodParams *minLodParams)
4123 	: m_numLevels		(numLevels)
4124 	, m_levels			(levels)
4125 	, m_es2				(es2)
4126 	, m_minLodParams	(minLodParams)
4127 {
4128 }
4129 
4130 // Texture3D
4131 
Texture3D(const TextureFormat & format,int width,int height,int depth)4132 Texture3D::Texture3D (const TextureFormat& format, int width, int height, int depth)
4133 	: TextureLevelPyramid	(format, computeMipPyramidLevels(width, height, depth))
4134 	, m_width				(width)
4135 	, m_height				(height)
4136 	, m_depth				(depth)
4137 	, m_view				(getNumLevels(), getLevels())
4138 {
4139 }
4140 
Texture3D(const Texture3D & other)4141 Texture3D::Texture3D (const Texture3D& other)
4142 	: TextureLevelPyramid	(other)
4143 	, m_width				(other.m_width)
4144 	, m_height				(other.m_height)
4145 	, m_depth				(other.m_depth)
4146 	, m_view				(getNumLevels(), getLevels())
4147 {
4148 }
4149 
operator =(const Texture3D & other)4150 Texture3D& Texture3D::operator= (const Texture3D& other)
4151 {
4152 	if (this == &other)
4153 		return *this;
4154 
4155 	TextureLevelPyramid::operator=(other);
4156 
4157 	m_width		= other.m_width;
4158 	m_height	= other.m_height;
4159 	m_depth		= other.m_depth;
4160 	m_view		= Texture3DView(getNumLevels(), getLevels());
4161 
4162 	return *this;
4163 }
4164 
~Texture3D(void)4165 Texture3D::~Texture3D (void)
4166 {
4167 }
4168 
allocLevel(int levelNdx)4169 void Texture3D::allocLevel (int levelNdx)
4170 {
4171 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
4172 
4173 	const int width		= getMipPyramidLevelSize(m_width,	levelNdx);
4174 	const int height	= getMipPyramidLevelSize(m_height,	levelNdx);
4175 	const int depth		= getMipPyramidLevelSize(m_depth,	levelNdx);
4176 
4177 	TextureLevelPyramid::allocLevel(levelNdx, width, height, depth);
4178 }
4179 
4180 // TextureCubeArrayView
4181 
TextureCubeArrayView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR,ImageViewMinLodParams * minLodParams DE_UNUSED_ATTR)4182 TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR, ImageViewMinLodParams* minLodParams DE_UNUSED_ATTR)
4183 	: m_numLevels	(numLevels)
4184 	, m_levels		(levels)
4185 {
4186 }
4187 
selectLayer(float q) const4188 inline int TextureCubeArrayView::selectLayer (float q) const
4189 {
4190 	DE_ASSERT(m_numLevels > 0 && m_levels);
4191 	DE_ASSERT((m_levels[0].getDepth() % 6) == 0);
4192 
4193 	return de::clamp(deFloorFloatToInt32(q + 0.5f), 0, (m_levels[0].getDepth() / 6)-1);
4194 }
4195 
sample(const Sampler & sampler,float s,float t,float r,float q,float lod) const4196 tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const
4197 {
4198 	const CubeFaceFloatCoords	coords		= getCubeFaceCoords(Vec3(s, t, r));
4199 	const int					layer		= selectLayer(q);
4200 	const int					faceDepth	= (layer * 6) + getCubeArrayFaceIndex(coords.face);
4201 
4202 	DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
4203 
4204 	if (sampler.seamlessCubeMap)
4205 		return sampleCubeArraySeamless(m_levels, m_numLevels, layer, coords.face, sampler, coords.s, coords.t, lod);
4206 	else
4207 		return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod);
4208 }
4209 
sampleCompare(const Sampler & sampler,float ref,float s,float t,float r,float q,float lod) const4210 float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const
4211 {
4212 	const CubeFaceFloatCoords	coords		= getCubeFaceCoords(Vec3(s, t, r));
4213 	const int					layer		= selectLayer(q);
4214 	const int					faceDepth	= (layer * 6) + getCubeArrayFaceIndex(coords.face);
4215 
4216 	DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
4217 
4218 	if (sampler.seamlessCubeMap)
4219 		return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, layer, coords.face, sampler, ref, coords.s, coords.t, lod);
4220 	else
4221 		return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth));
4222 }
4223 
4224 // TextureCubeArray
4225 
TextureCubeArray(const TextureFormat & format,int size,int depth)4226 TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int depth)
4227 	: TextureLevelPyramid	(format, computeMipPyramidLevels(size))
4228 	, m_size				(size)
4229 	, m_depth				(depth)
4230 	, m_view				(getNumLevels(), getLevels())
4231 {
4232 	DE_ASSERT(m_depth % 6 == 0);
4233 }
4234 
TextureCubeArray(const TextureCubeArray & other)4235 TextureCubeArray::TextureCubeArray (const TextureCubeArray& other)
4236 	: TextureLevelPyramid	(other)
4237 	, m_size				(other.m_size)
4238 	, m_depth				(other.m_depth)
4239 	, m_view				(getNumLevels(), getLevels())
4240 {
4241 	DE_ASSERT(m_depth % 6 == 0);
4242 }
4243 
operator =(const TextureCubeArray & other)4244 TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
4245 {
4246 	if (this == &other)
4247 		return *this;
4248 
4249 	TextureLevelPyramid::operator=(other);
4250 
4251 	m_size	= other.m_size;
4252 	m_depth	= other.m_depth;
4253 	m_view	= TextureCubeArrayView(getNumLevels(), getLevels());
4254 
4255 	DE_ASSERT(m_depth % 6 == 0);
4256 
4257 	return *this;
4258 }
4259 
~TextureCubeArray(void)4260 TextureCubeArray::~TextureCubeArray (void)
4261 {
4262 }
4263 
allocLevel(int levelNdx)4264 void TextureCubeArray::allocLevel (int levelNdx)
4265 {
4266 	DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
4267 
4268 	const int size = getMipPyramidLevelSize(m_size, levelNdx);
4269 
4270 	TextureLevelPyramid::allocLevel(levelNdx, size, size, m_depth);
4271 }
4272 
operator <<(std::ostream & str,TextureFormat::ChannelOrder order)4273 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order)
4274 {
4275 	const char* const orderStrings[] =
4276 	{
4277 		"R",
4278 		"A",
4279 		"I",
4280 		"L",
4281 		"LA",
4282 		"RG",
4283 		"RA",
4284 		"RGB",
4285 		"RGBA",
4286 		"ARGB",
4287 		"ABGR",
4288 		"BGR",
4289 		"BGRA",
4290 
4291 		"sR",
4292 		"sRG",
4293 		"sRGB",
4294 		"sRGBA",
4295 		"sBGR",
4296 		"sBGRA",
4297 
4298 		"D",
4299 		"S",
4300 		"DS"
4301 	};
4302 
4303 	return str << de::getSizedArrayElement<TextureFormat::CHANNELORDER_LAST>(orderStrings, order);
4304 }
4305 
operator <<(std::ostream & str,TextureFormat::ChannelType type)4306 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelType type)
4307 {
4308 	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
4309 
4310 	const char* const typeStrings[] =
4311 	{
4312 		"SNORM_INT8",
4313 		"SNORM_INT16",
4314 		"SNORM_INT32",
4315 		"UNORM_INT8",
4316 		"UNORM_INT16",
4317 		"UNORM_INT24",
4318 		"UNORM_INT32",
4319 		"UNORM_BYTE_44",
4320 		"UNORM_SHORT_565",
4321 		"UNORM_SHORT_555",
4322 		"UNORM_SHORT_4444",
4323 		"UNORM_SHORT_5551",
4324 		"UNORM_SHORT_1555",
4325 		"UNORM_INT_101010",
4326 		"SNORM_INT_1010102_REV",
4327 		"UNORM_INT_1010102_REV",
4328 		"UNSIGNED_BYTE_44",
4329 		"UNSIGNED_SHORT_565",
4330 		"UNSIGNED_SHORT_4444",
4331 		"UNSIGNED_SHORT_5551",
4332 		"SIGNED_INT_1010102_REV",
4333 		"UNSIGNED_INT_1010102_REV",
4334 		"UNSIGNED_INT_11F_11F_10F_REV",
4335 		"UNSIGNED_INT_999_E5_REV",
4336 		"UNSIGNED_INT_16_8_8",
4337 		"UNSIGNED_INT_24_8",
4338 		"UNSIGNED_INT_24_8_REV",
4339 		"SIGNED_INT8",
4340 		"SIGNED_INT16",
4341 		"SIGNED_INT32",
4342 		"SIGNED_INT64",
4343 		"UNSIGNED_INT8",
4344 		"UNSIGNED_INT16",
4345 		"UNSIGNED_INT24",
4346 		"UNSIGNED_INT32",
4347 		"UNSIGNED_INT64",
4348 		"HALF_FLOAT",
4349 		"FLOAT",
4350 		"FLOAT64",
4351 		"FLOAT_UNSIGNED_INT_24_8_REV",
4352 		"UNORM_SHORT_10",
4353 		"UNORM_SHORT_12",
4354 		"USCALED_INT8",
4355 		"USCALED_INT16",
4356 		"SSCALED_INT8",
4357 		"SSCALED_INT16",
4358 		"USCALED_INT_1010102_REV",
4359 		"SSCALED_INT_1010102_REV"
4360 	};
4361 
4362 	return str << de::getSizedArrayElement<TextureFormat::CHANNELTYPE_LAST>(typeStrings, type);
4363 }
4364 
operator <<(std::ostream & str,CubeFace face)4365 std::ostream& operator<< (std::ostream& str, CubeFace face)
4366 {
4367 	switch (face)
4368 	{
4369 		case CUBEFACE_NEGATIVE_X:	return str << "CUBEFACE_NEGATIVE_X";
4370 		case CUBEFACE_POSITIVE_X:	return str << "CUBEFACE_POSITIVE_X";
4371 		case CUBEFACE_NEGATIVE_Y:	return str << "CUBEFACE_NEGATIVE_Y";
4372 		case CUBEFACE_POSITIVE_Y:	return str << "CUBEFACE_POSITIVE_Y";
4373 		case CUBEFACE_NEGATIVE_Z:	return str << "CUBEFACE_NEGATIVE_Z";
4374 		case CUBEFACE_POSITIVE_Z:	return str << "CUBEFACE_POSITIVE_Z";
4375 		case CUBEFACE_LAST:			return str << "CUBEFACE_LAST";
4376 		default:					return str << "UNKNOWN(" << (int)face << ")";
4377 	}
4378 }
4379 
operator <<(std::ostream & str,TextureFormat format)4380 std::ostream& operator<< (std::ostream& str, TextureFormat format)
4381 {
4382 	return str << format.order << ", " << format.type << "";
4383 }
4384 
operator <<(std::ostream & str,const ConstPixelBufferAccess & access)4385 std::ostream& operator<< (std::ostream& str, const ConstPixelBufferAccess& access)
4386 {
4387 	return str << "format = (" << access.getFormat() << "), size = "
4388 			   << access.getWidth() << " x " << access.getHeight() << " x " << access.getDepth()
4389 			   << ", pitch = " << access.getRowPitch() << " / " << access.getSlicePitch();
4390 }
4391 
isSamplerMipmapModeLinear(tcu::Sampler::FilterMode filterMode)4392 deBool isSamplerMipmapModeLinear (tcu::Sampler::FilterMode filterMode)
4393 {
4394 	DE_STATIC_ASSERT(tcu::Sampler::FILTERMODE_LAST == 9);
4395 	switch (filterMode)
4396 	{
4397 		case tcu::Sampler::NEAREST:
4398 		case tcu::Sampler::LINEAR:
4399 		case tcu::Sampler::CUBIC:
4400 		case tcu::Sampler::NEAREST_MIPMAP_NEAREST:
4401 		case tcu::Sampler::LINEAR_MIPMAP_NEAREST:
4402 		case tcu::Sampler::CUBIC_MIPMAP_NEAREST:
4403 			return DE_FALSE;
4404 		case tcu::Sampler::NEAREST_MIPMAP_LINEAR:
4405 		case tcu::Sampler::LINEAR_MIPMAP_LINEAR:
4406 		case tcu::Sampler::CUBIC_MIPMAP_LINEAR:
4407 			return DE_TRUE;
4408 		default:
4409 			DE_FATAL("Illegal filter mode");
4410 			return DE_FALSE;
4411 	}
4412 }
4413 } // tcu
4414