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