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