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