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