Add support for 10 and 12bit packed unorm formats
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuTexture.cpp
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
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); }
52 inline Vec4             readRGB888Float         (const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, 1.0f); }
53 inline IVec4    readRGBA8888Int         (const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], ptr[3]); }
54 inline IVec4    readRGB888Int           (const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], 1); }
55
56 // Optimized setters.
57
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
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
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
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
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
101 inline deUint32 readUint24 (const deUint8* src)
102 {
103 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
104         return  (((deUint32)src[0]) <<  0u) |
105                         (((deUint32)src[1]) <<  8u) |
106                         (((deUint32)src[2]) << 16u);
107 #else
108         return  (((deUint32)src[0]) << 16u) |
109                         (((deUint32)src[1]) <<  8u) |
110                         (((deUint32)src[2]) <<  0u);
111 #endif
112 }
113
114 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
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
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
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
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
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
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
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
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
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>
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
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
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
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
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
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
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>
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>
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>
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>
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
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
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
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
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
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
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
497 inline deUint32 uintToChannel (deUint32 src, int bits)
498 {
499         const deUint32 maxVal = (1u << bits) - 1;
500         return de::min(src, maxVal);
501 }
502
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
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
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
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
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
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. */
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
762 int TextureFormat::getPixelSize (void) const
763 {
764         return ::tcu::getPixelSize(*this);
765 }
766
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
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
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
884 ConstPixelBufferAccess::ConstPixelBufferAccess (void)
885         : m_size                (0)
886         , m_pitch               (0)
887         , m_data                (DE_NULL)
888 {
889 }
890
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
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
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
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
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
936 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data)
937         : ConstPixelBufferAccess(format, width, height, depth, data)
938 {
939 }
940
941 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, void* data)
942         : ConstPixelBufferAccess(format, size, data)
943 {
944 }
945
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
951 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, void* data)
952         : ConstPixelBufferAccess(format, size, pitch, data)
953 {
954 }
955
956 PixelBufferAccess::PixelBufferAccess (TextureLevel& level)
957         : ConstPixelBufferAccess(level)
958 {
959 }
960
961 //! Swizzle RGB(A) <-> BGR(A)
962 template<typename T>
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
977 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
1076 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<>
1163 Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1164 {
1165         return getPixel(x, y, z);
1166 }
1167
1168 template<>
1169 IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1170 {
1171         return getPixelInt(x, y, z);
1172 }
1173
1174 template<>
1175 UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1176 {
1177         return getPixelUint(x, y, z);
1178 }
1179
1180 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
1212 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
1243 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
1393 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
1501 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
1538 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
1571 static inline int imod (int a, int b)
1572 {
1573         int m = a % b;
1574         return m < 0 ? m + b : m;
1575 }
1576
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.
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
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.
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
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.
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.
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
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
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
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
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
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
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
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
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
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
1977 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
1985 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
1993 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
1998 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
2020 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
2046 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
2070 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
2095 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
2124 TextureLevel::TextureLevel (void)
2125         : m_format      ()
2126         , m_size        (0)
2127 {
2128 }
2129
2130 TextureLevel::TextureLevel (const TextureFormat& format)
2131         : m_format      (format)
2132         , m_size        (0)
2133 {
2134 }
2135
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
2143 TextureLevel::~TextureLevel (void)
2144 {
2145 }
2146
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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
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
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
3088 inline int computeMipPyramidLevels (int size)
3089 {
3090         return deLog2Floor32(size)+1;
3091 }
3092
3093 inline int computeMipPyramidLevels (int width, int height)
3094 {
3095         return deLog2Floor32(de::max(width, height))+1;
3096 }
3097
3098 inline int computeMipPyramidLevels (int width, int height, int depth)
3099 {
3100         return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
3101 }
3102
3103 inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx)
3104 {
3105         return de::max(baseLevelSize >> levelNdx, 1);
3106 }
3107
3108 // TextureLevelPyramid
3109
3110 TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels)
3111         : m_format      (format)
3112         , m_data        (numLevels)
3113         , m_access      (numLevels)
3114 {
3115 }
3116
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
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
3159 TextureLevelPyramid::~TextureLevelPyramid (void)
3160 {
3161 }
3162
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
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
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
3190 Texture1D::Texture1D (const Texture1D& other)
3191         : TextureLevelPyramid   (other)
3192         , m_width                               (other.m_width)
3193         , m_view                                (getNumLevels(), getLevels())
3194 {
3195 }
3196
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
3210 Texture1D::~Texture1D (void)
3211 {
3212 }
3213
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
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
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
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
3255 Texture2D::~Texture2D (void)
3256 {
3257 }
3258
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
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
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
3285 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
3297 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
3309 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
3340 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
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
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
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
3445 TextureCube::~TextureCube (void)
3446 {
3447 }
3448
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
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
3468 Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3469         : m_numLevels   (numLevels)
3470         , m_levels              (levels)
3471 {
3472 }
3473
3474 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
3480 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
3485 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
3490 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
3495 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
3502 Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3503         : m_numLevels   (numLevels)
3504         , m_levels              (levels)
3505 {
3506 }
3507
3508 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
3514 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
3519 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
3524 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
3529 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
3534 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
3539 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
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
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
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
3576 Texture1DArray::~Texture1DArray (void)
3577 {
3578 }
3579
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
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
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
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
3624 Texture2DArray::~Texture2DArray (void)
3625 {
3626 }
3627
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
3640 Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels)
3641         : m_numLevels   (numLevels)
3642         , m_levels              (levels)
3643 {
3644 }
3645
3646 // Texture3D
3647
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
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
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
3681 Texture3D::~Texture3D (void)
3682 {
3683 }
3684
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
3698 TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3699         : m_numLevels   (numLevels)
3700         , m_levels              (levels)
3701 {
3702 }
3703
3704 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
3712 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
3726 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
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
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
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
3776 TextureCubeArray::~TextureCubeArray (void)
3777 {
3778 }
3779
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
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
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
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
3885 std::ostream& operator<< (std::ostream& str, TextureFormat format)
3886 {
3887         return str << format.order << ", " << format.type << "";
3888 }
3889
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