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