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