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