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