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