1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Reference Texture Implementation.
22 *//*--------------------------------------------------------------------*/
24 #include "tcuTexture.hpp"
26 #include "deFloat16.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"
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;
48 // Optimized getters for common formats.
49 // \todo [2012-11-14 pyry] Use intrinsics if available.
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); }
58 inline void writeRGBA8888Int (deUint8* ptr, const IVec4& val)
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);
66 inline void writeRGB888Int (deUint8* ptr, const IVec4& val)
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);
73 inline void writeRGBA8888Float (deUint8* ptr, const Vec4& val)
75 ptr[0] = floatToU8(val[0]);
76 ptr[1] = floatToU8(val[1]);
77 ptr[2] = floatToU8(val[2]);
78 ptr[3] = floatToU8(val[3]);
81 inline void writeRGB888Float (deUint8* ptr, const Vec4& val)
83 ptr[0] = floatToU8(val[0]);
84 ptr[1] = floatToU8(val[1]);
85 ptr[2] = floatToU8(val[2]);
88 inline void writeUint24 (deUint8* dst, deUint32 val)
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);
95 dst[0] = (deUint8)((val & 0xFF0000u) >> 16u);
96 dst[1] = (deUint8)((val & 0x00FF00u) >> 8u);
97 dst[2] = (deUint8)((val & 0x0000FFu) >> 0u);
101 inline deUint32 readUint24 (const deUint8* src)
103 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
104 return (((deUint32)src[0]) << 0u) |
105 (((deUint32)src[1]) << 8u) |
106 (((deUint32)src[2]) << 16u);
108 return (((deUint32)src[0]) << 16u) |
109 (((deUint32)src[1]) << 8u) |
110 (((deUint32)src[2]) << 0u);
114 inline deUint8 readUint32Low8 (const deUint8* src)
116 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
117 const deUint32 uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
119 const deUint32 uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
122 return src[uint32ByteOffsetBits0To8];
125 inline deUint8 readUint32High8 (const deUint8* src)
127 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
128 const deUint32 uint32ByteOffsetBits24To32 = 3;
130 const deUint32 uint32ByteOffsetBits24To32 = 0;
133 return src[uint32ByteOffsetBits24To32];
136 inline void writeUint32Low8 (deUint8* dst, deUint8 val)
138 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
139 const deUint32 uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
141 const deUint32 uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
144 dst[uint32ByteOffsetBits0To8] = val;
147 inline void writeUint32High8 (deUint8* dst, deUint8 val)
149 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
150 const deUint32 uint32ByteOffsetBits24To32 = 3;
152 const deUint32 uint32ByteOffsetBits24To32 = 0;
155 dst[uint32ByteOffsetBits24To32] = val;
158 inline deUint32 readUint32High16 (const deUint8* src)
160 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
161 const deUint32 uint32ByteOffset16To32 = 2;
163 const deUint32 uint32ByteOffset16To32 = 0;
166 return *(const deUint16*)(src + uint32ByteOffset16To32);
169 inline void writeUint32High16 (deUint8* dst, deUint16 val)
171 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
172 const deUint32 uint32ByteOffset16To32 = 2;
174 const deUint32 uint32ByteOffset16To32 = 0;
177 *(deUint16*)(dst + uint32ByteOffset16To32) = val;
180 inline deUint32 readUint32Low24 (const deUint8* src)
182 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
183 const deUint32 uint32ByteOffset0To24 = 0;
185 const deUint32 uint32ByteOffset0To24 = 1;
188 return readUint24(src + uint32ByteOffset0To24);
191 inline deUint32 readUint32High24 (const deUint8* src)
193 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
194 const deUint32 uint32ByteOffset8To32 = 1;
196 const deUint32 uint32ByteOffset8To32 = 0;
199 return readUint24(src + uint32ByteOffset8To32);
202 inline void writeUint32Low24 (deUint8* dst, deUint32 val)
204 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
205 const deUint32 uint32ByteOffset0To24 = 0;
207 const deUint32 uint32ByteOffset0To24 = 1;
210 writeUint24(dst + uint32ByteOffset0To24, val);
213 inline void writeUint32High24 (deUint8* dst, deUint32 val)
215 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
216 const deUint32 uint32ByteOffset8To32 = 1;
218 const deUint32 uint32ByteOffset8To32 = 0;
221 writeUint24(dst + uint32ByteOffset8To32, val);
224 // \todo [2011-09-21 pyry] Move to tcutil?
225 template <typename T>
226 inline T convertSatRte (float f)
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));
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);
245 // else Don't add anything
248 intVal = de::max(minVal, de::min(maxVal, intVal));
253 inline deUint32 convertSatRteUint24 (float f)
255 const deUint32 rounded = convertSatRte<deUint32>(f);
256 const deUint32 maxUint24 = 0xFFFFFFu;
257 return de::min(rounded, maxUint24);
260 int getChannelSize (TextureFormat::ChannelType type)
262 // make sure this table is updated if format table is updated
263 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
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;
290 inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
292 // make sure this table is updated if format table is updated
293 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
297 case TextureFormat::SNORM_INT8: return de::max(-1.0f, (float)*((const deInt8*)value) / 127.0f);
298 case TextureFormat::SNORM_INT16: return de::max(-1.0f, (float)*((const deInt16*)value) / 32767.0f);
299 case TextureFormat::SNORM_INT32: return de::max(-1.0f, (float)*((const deInt32*)value) / 2147483647.0f);
300 case TextureFormat::UNORM_INT8: return (float)*((const deUint8*)value) / 255.0f;
301 case TextureFormat::UNORM_INT16: return (float)*((const deUint16*)value) / 65535.0f;
302 case TextureFormat::UNORM_INT24: return (float)readUint24(value) / 16777215.0f;
303 case TextureFormat::UNORM_INT32: return (float)*((const deUint32*)value) / 4294967295.0f;
304 case TextureFormat::SIGNED_INT8: return (float)*((const deInt8*)value);
305 case TextureFormat::SIGNED_INT16: return (float)*((const deInt16*)value);
306 case TextureFormat::SIGNED_INT32: return (float)*((const deInt32*)value);
307 case TextureFormat::UNSIGNED_INT8: return (float)*((const deUint8*)value);
308 case TextureFormat::UNSIGNED_INT16: return (float)*((const deUint16*)value);
309 case TextureFormat::UNSIGNED_INT24: return (float)readUint24(value);
310 case TextureFormat::UNSIGNED_INT32: return (float)*((const deUint32*)value);
311 case TextureFormat::HALF_FLOAT: return deFloat16To32(*(const deFloat16*)value);
312 case TextureFormat::FLOAT: return *((const float*)value);
313 case TextureFormat::FLOAT64: return (float)*((const double*)value);
320 inline int channelToInt (const deUint8* value, TextureFormat::ChannelType type)
322 // make sure this table is updated if format table is updated
323 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
327 case TextureFormat::SNORM_INT8: return (int)*((const deInt8*)value);
328 case TextureFormat::SNORM_INT16: return (int)*((const deInt16*)value);
329 case TextureFormat::SNORM_INT32: return (int)*((const deInt32*)value);
330 case TextureFormat::UNORM_INT8: return (int)*((const deUint8*)value);
331 case TextureFormat::UNORM_INT16: return (int)*((const deUint16*)value);
332 case TextureFormat::UNORM_INT24: return (int)readUint24(value);
333 case TextureFormat::UNORM_INT32: return (int)*((const deUint32*)value);
334 case TextureFormat::SIGNED_INT8: return (int)*((const deInt8*)value);
335 case TextureFormat::SIGNED_INT16: return (int)*((const deInt16*)value);
336 case TextureFormat::SIGNED_INT32: return (int)*((const deInt32*)value);
337 case TextureFormat::UNSIGNED_INT8: return (int)*((const deUint8*)value);
338 case TextureFormat::UNSIGNED_INT16: return (int)*((const deUint16*)value);
339 case TextureFormat::UNSIGNED_INT24: return (int)readUint24(value);
340 case TextureFormat::UNSIGNED_INT32: return (int)*((const deUint32*)value);
341 case TextureFormat::HALF_FLOAT: return (int)deFloat16To32(*(const deFloat16*)value);
342 case TextureFormat::FLOAT: return (int)*((const float*)value);
343 case TextureFormat::FLOAT64: return (int)*((const double*)value);
350 void floatToChannel (deUint8* dst, float src, TextureFormat::ChannelType type)
352 // make sure this table is updated if format table is updated
353 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
357 case TextureFormat::SNORM_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src * 127.0f); break;
358 case TextureFormat::SNORM_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src * 32767.0f); break;
359 case TextureFormat::SNORM_INT32: *((deInt32*)dst) = convertSatRte<deInt32> (src * 2147483647.0f); break;
360 case TextureFormat::UNORM_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src * 255.0f); break;
361 case TextureFormat::UNORM_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src * 65535.0f); break;
362 case TextureFormat::UNORM_INT24: writeUint24(dst, convertSatRteUint24 (src * 16777215.0f)); break;
363 case TextureFormat::UNORM_INT32: *((deUint32*)dst) = convertSatRte<deUint32> (src * 4294967295.0f); break;
364 case TextureFormat::SIGNED_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src); break;
365 case TextureFormat::SIGNED_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src); break;
366 case TextureFormat::SIGNED_INT32: *((deInt32*)dst) = convertSatRte<deInt32> (src); break;
367 case TextureFormat::UNSIGNED_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src); break;
368 case TextureFormat::UNSIGNED_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src); break;
369 case TextureFormat::UNSIGNED_INT24: writeUint24(dst, convertSatRteUint24 (src)); break;
370 case TextureFormat::UNSIGNED_INT32: *((deUint32*)dst) = convertSatRte<deUint32> (src); break;
371 case TextureFormat::HALF_FLOAT: *((deFloat16*)dst) = deFloat32To16 (src); break;
372 case TextureFormat::FLOAT: *((float*)dst) = src; break;
373 case TextureFormat::FLOAT64: *((double*)dst) = (double)src; break;
379 template <typename T, typename S>
380 static inline T convertSat (S src)
382 S min = (S)std::numeric_limits<T>::min();
383 S max = (S)std::numeric_limits<T>::max();
393 template <typename S>
394 static inline deUint32 convertSatUint24 (S src)
397 S max = (S)0xFFFFFFu;
400 return (deUint32)min;
402 return (deUint32)max;
404 return (deUint32)src;
407 void intToChannel (deUint8* dst, int src, TextureFormat::ChannelType type)
409 // make sure this table is updated if format table is updated
410 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
414 case TextureFormat::SNORM_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
415 case TextureFormat::SNORM_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
416 case TextureFormat::UNORM_INT8: *((deUint8*)dst) = convertSat<deUint8> (src); break;
417 case TextureFormat::UNORM_INT16: *((deUint16*)dst) = convertSat<deUint16> (src); break;
418 case TextureFormat::UNORM_INT24: writeUint24(dst, convertSatUint24 (src)); break;
419 case TextureFormat::SIGNED_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
420 case TextureFormat::SIGNED_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
421 case TextureFormat::SIGNED_INT32: *((deInt32*)dst) = convertSat<deInt32> (src); break;
422 case TextureFormat::UNSIGNED_INT8: *((deUint8*)dst) = convertSat<deUint8> ((deUint32)src); break;
423 case TextureFormat::UNSIGNED_INT16: *((deUint16*)dst) = convertSat<deUint16> ((deUint32)src); break;
424 case TextureFormat::UNSIGNED_INT24: writeUint24(dst, convertSatUint24 ((deUint32)src)); break;
425 case TextureFormat::UNSIGNED_INT32: *((deUint32*)dst) = convertSat<deUint32> ((deUint32)src); break;
426 case TextureFormat::HALF_FLOAT: *((deFloat16*)dst) = deFloat32To16((float)src); break;
427 case TextureFormat::FLOAT: *((float*)dst) = (float)src; break;
428 case TextureFormat::FLOAT64: *((double*)dst) = (double)src; break;
434 inline float channelToUnormFloat (deUint32 src, int bits)
436 const deUint32 maxVal = (1u << bits) - 1;
438 // \note Will lose precision if bits > 23
439 return (float)src / (float)maxVal;
442 //! Extend < 32b signed integer to 32b
443 inline deInt32 signExtend (deUint32 src, int bits)
445 const deUint32 signBit = 1u << (bits-1);
447 src |= ~((src & signBit) - 1);
452 inline float channelToSnormFloat (deUint32 src, int bits)
454 const deUint32 range = (1u << (bits-1)) - 1;
456 // \note Will lose precision if bits > 24
457 return de::max(-1.0f, (float)signExtend(src, bits) / (float)range);
460 inline deUint32 unormFloatToChannel (float src, int bits)
462 const deUint32 maxVal = (1u << bits) - 1;
463 const deUint32 intVal = convertSatRte<deUint32>(src * (float)maxVal);
465 return de::min(intVal, maxVal);
468 inline deUint32 snormFloatToChannel (float src, int bits)
470 const deInt32 range = (deInt32)((1u << (bits-1)) - 1u);
471 const deUint32 mask = (1u << bits) - 1;
472 const deInt32 intVal = convertSatRte<deInt32>(src * (float)range);
474 return (deUint32)de::clamp(intVal, -range, range) & mask;
477 inline deUint32 uintToChannel (deUint32 src, int bits)
479 const deUint32 maxVal = (1u << bits) - 1;
480 return de::min(src, maxVal);
483 inline deUint32 intToChannel (deInt32 src, int bits)
485 const deInt32 minVal = -(deInt32)(1u << (bits-1));
486 const deInt32 maxVal = (deInt32)((1u << (bits-1)) - 1u);
487 const deUint32 mask = (1u << bits) - 1;
489 return (deUint32)de::clamp(src, minVal, maxVal) & mask;
492 tcu::Vec4 unpackRGB999E5 (deUint32 color)
495 const int eBias = 15;
497 deUint32 exp = color >> 27;
498 deUint32 bs = (color >> 18) & ((1<<9)-1);
499 deUint32 gs = (color >> 9) & ((1<<9)-1);
500 deUint32 rs = color & ((1<<9)-1);
502 float e = deFloatPow(2.0f, (float)((int)exp - eBias - mBits));
503 float r = (float)rs * e;
504 float g = (float)gs * e;
505 float b = (float)bs * e;
507 return tcu::Vec4(r, g, b, 1.0f);
510 bool isColorOrder (TextureFormat::ChannelOrder order)
512 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
516 case TextureFormat::R:
517 case TextureFormat::A:
518 case TextureFormat::I:
519 case TextureFormat::L:
520 case TextureFormat::LA:
521 case TextureFormat::RG:
522 case TextureFormat::RA:
523 case TextureFormat::RGB:
524 case TextureFormat::RGBA:
525 case TextureFormat::ARGB:
526 case TextureFormat::BGR:
527 case TextureFormat::BGRA:
528 case TextureFormat::sR:
529 case TextureFormat::sRG:
530 case TextureFormat::sRGB:
531 case TextureFormat::sRGBA:
532 case TextureFormat::sBGR:
533 case TextureFormat::sBGRA:
543 bool isValid (TextureFormat format)
545 const bool isColor = isColorOrder(format.order);
549 case TextureFormat::SNORM_INT8:
550 case TextureFormat::SNORM_INT16:
551 case TextureFormat::SNORM_INT32:
554 case TextureFormat::UNORM_INT8:
555 case TextureFormat::UNORM_INT16:
556 case TextureFormat::UNORM_INT24:
557 case TextureFormat::UNORM_INT32:
558 return isColor || format.order == TextureFormat::D;
560 case TextureFormat::UNORM_BYTE_44:
561 case TextureFormat::UNSIGNED_BYTE_44:
562 return format.order == TextureFormat::RG;
564 case TextureFormat::UNORM_SHORT_565:
565 case TextureFormat::UNORM_SHORT_555:
566 case TextureFormat::UNSIGNED_SHORT_565:
567 return format.order == TextureFormat::RGB || format.order == TextureFormat::BGR;
569 case TextureFormat::UNORM_SHORT_4444:
570 case TextureFormat::UNORM_SHORT_5551:
571 case TextureFormat::UNSIGNED_SHORT_4444:
572 case TextureFormat::UNSIGNED_SHORT_5551:
573 return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
575 case TextureFormat::UNORM_SHORT_1555:
576 return format.order == TextureFormat::ARGB;
578 case TextureFormat::UNORM_INT_101010:
579 return format.order == TextureFormat::RGB;
581 case TextureFormat::SNORM_INT_1010102_REV:
582 case TextureFormat::UNORM_INT_1010102_REV:
583 case TextureFormat::SIGNED_INT_1010102_REV:
584 case TextureFormat::UNSIGNED_INT_1010102_REV:
585 return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
587 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
588 case TextureFormat::UNSIGNED_INT_999_E5_REV:
589 return format.order == TextureFormat::RGB;
591 case TextureFormat::UNSIGNED_INT_16_8_8:
592 return format.order == TextureFormat::DS;
594 case TextureFormat::UNSIGNED_INT_24_8:
595 case TextureFormat::UNSIGNED_INT_24_8_REV:
596 return format.order == TextureFormat::D || format.order == TextureFormat::DS;
598 case TextureFormat::SIGNED_INT8:
599 case TextureFormat::SIGNED_INT16:
600 case TextureFormat::SIGNED_INT32:
603 case TextureFormat::UNSIGNED_INT8:
604 case TextureFormat::UNSIGNED_INT16:
605 case TextureFormat::UNSIGNED_INT24:
606 case TextureFormat::UNSIGNED_INT32:
607 return isColor || format.order == TextureFormat::S;
609 case TextureFormat::HALF_FLOAT:
610 case TextureFormat::FLOAT:
611 case TextureFormat::FLOAT64:
612 return isColor || format.order == TextureFormat::D;
614 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
615 return format.order == TextureFormat::DS;
618 DE_FATAL("Unknown format");
622 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
625 int getNumUsedChannels (TextureFormat::ChannelOrder order)
627 // make sure this table is updated if type table is updated
628 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
632 case TextureFormat::R: return 1;
633 case TextureFormat::A: return 1;
634 case TextureFormat::I: return 1;
635 case TextureFormat::L: return 1;
636 case TextureFormat::LA: return 2;
637 case TextureFormat::RG: return 2;
638 case TextureFormat::RA: return 2;
639 case TextureFormat::RGB: return 3;
640 case TextureFormat::RGBA: return 4;
641 case TextureFormat::ARGB: return 4;
642 case TextureFormat::BGR: return 3;
643 case TextureFormat::BGRA: return 4;
644 case TextureFormat::sR: return 1;
645 case TextureFormat::sRG: return 2;
646 case TextureFormat::sRGB: return 3;
647 case TextureFormat::sRGBA: return 4;
648 case TextureFormat::sBGR: return 3;
649 case TextureFormat::sBGRA: return 4;
650 case TextureFormat::D: return 1;
651 case TextureFormat::S: return 1;
652 case TextureFormat::DS: return 2;
659 /** Get pixel size in bytes. */
660 int getPixelSize (TextureFormat format)
662 const TextureFormat::ChannelOrder order = format.order;
663 const TextureFormat::ChannelType type = format.type;
665 DE_ASSERT(isValid(format));
667 // make sure this table is updated if format table is updated
668 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
672 case TextureFormat::UNORM_BYTE_44:
673 case TextureFormat::UNSIGNED_BYTE_44:
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:
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:
698 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
702 return getNumUsedChannels(order) * getChannelSize(type);
706 int TextureFormat::getPixelSize (void) const
708 return ::tcu::getPixelSize(*this);
711 const TextureSwizzle& getChannelReadSwizzle (TextureFormat::ChannelOrder order)
713 // make sure to update these tables when channel orders are updated
714 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
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 }};
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;
755 case TextureFormat::DS:
756 DE_ASSERT(false); // combined formats cannot be read from
765 const TextureSwizzle& getChannelWriteSwizzle (TextureFormat::ChannelOrder order)
767 // make sure to update these tables when channel orders are updated
768 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
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 }};
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;
809 case TextureFormat::DS:
810 DE_ASSERT(false); // combined formats cannot be written to
819 IVec3 calculatePackedPitch (const TextureFormat& format, const IVec3& size)
821 const int pixelSize = format.getPixelSize();
822 const int rowPitch = pixelSize * size.x();
823 const int slicePitch = rowPitch * size.y();
825 return IVec3(pixelSize, rowPitch, slicePitch);
828 ConstPixelBufferAccess::ConstPixelBufferAccess (void)
835 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, const void* data)
837 , m_size (width, height, depth)
838 , m_pitch (calculatePackedPitch(m_format, m_size))
839 , m_data ((void*)data)
841 DE_ASSERT(isValid(format));
844 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const void* data)
847 , m_pitch (calculatePackedPitch(m_format, m_size))
848 , m_data ((void*)data)
850 DE_ASSERT(isValid(format));
853 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, const void* data)
855 , m_size (width, height, depth)
856 , m_pitch (format.getPixelSize(), rowPitch, slicePitch)
857 , m_data ((void*)data)
859 DE_ASSERT(isValid(format));
862 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, const void* data)
866 , m_data ((void*)data)
868 DE_ASSERT(isValid(format));
869 DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
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())
880 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data)
881 : ConstPixelBufferAccess(format, width, height, depth, data)
885 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, void* data)
886 : ConstPixelBufferAccess(format, size, data)
890 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, void* data)
891 : ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, data)
895 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, void* data)
896 : ConstPixelBufferAccess(format, size, pitch, data)
900 PixelBufferAccess::PixelBufferAccess (TextureLevel& level)
901 : ConstPixelBufferAccess(level)
905 //! Swizzle RGB(A) <-> BGR(A)
907 Vector<T, 4> swizzleRB (const Vector<T, 4>& v, TextureFormat::ChannelOrder src, TextureFormat::ChannelOrder dst)
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);
921 Vec4 ConstPixelBufferAccess::getPixel (int x, int y, int z) const
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
929 const deUint8* pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
932 if (m_format.type == TextureFormat::UNORM_INT8)
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);
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))
950 switch (m_format.type)
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));
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
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);
990 const TextureSwizzle::Channel* channelMap = getChannelReadSwizzle(m_format.order).components;
991 int channelSize = getChannelSize(m_format.type);
993 for (int c = 0; c < 4; c++)
995 switch (channelMap[c])
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);
1004 case TextureSwizzle::CHANNEL_ZERO:
1008 case TextureSwizzle::CHANNEL_ONE:
1020 IVec4 ConstPixelBufferAccess::getPixelInt (int x, int y, int z) const
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
1028 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1031 // Optimized fomats.
1032 if (m_format.type == TextureFormat::UNORM_INT8)
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);
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))
1045 switch (m_format.type)
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);
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
1067 break; // To generic path.
1076 const TextureSwizzle::Channel* channelMap = getChannelReadSwizzle(m_format.order).components;
1077 int channelSize = getChannelSize(m_format.type);
1079 for (int c = 0; c < 4; c++)
1081 switch (channelMap[c])
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);
1090 case TextureSwizzle::CHANNEL_ZERO:
1094 case TextureSwizzle::CHANNEL_ONE:
1107 Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1109 return getPixel(x, y, z);
1113 IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1115 return getPixelInt(x, y, z);
1119 UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1121 return getPixelUint(x, y, z);
1124 float ConstPixelBufferAccess::getPixDepth (int x, int y, int z) const
1126 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1127 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1128 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1130 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1132 switch (m_format.type)
1134 case TextureFormat::UNSIGNED_INT_16_8_8:
1135 DE_ASSERT(m_format.order == TextureFormat::DS);
1136 return (float)readUint32High16(pixelPtr) / 65535.0f;
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;
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;
1146 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1147 DE_ASSERT(m_format.order == TextureFormat::DS);
1148 return *((const float*)pixelPtr);
1151 DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1152 return channelToFloat(pixelPtr, m_format.type);
1156 int ConstPixelBufferAccess::getPixStencil (int x, int y, int z) const
1158 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1159 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1160 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1162 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1164 switch (m_format.type)
1166 case TextureFormat::UNSIGNED_INT_24_8_REV:
1167 DE_ASSERT(m_format.order == TextureFormat::DS);
1168 return (int)readUint32High8(pixelPtr);
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);
1175 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1176 DE_ASSERT(m_format.order == TextureFormat::DS);
1177 return (int)readUint32Low8(pixelPtr + 4);
1181 DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1182 return channelToInt(pixelPtr, m_format.type);
1187 void PixelBufferAccess::setPixel (const Vec4& color, int x, int y, int z) const
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
1195 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1197 // Optimized fomats.
1198 if (m_format.type == TextureFormat::UNORM_INT8)
1200 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1202 writeRGBA8888Float(pixelPtr, color);
1205 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1207 writeRGB888Float(pixelPtr, color);
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))
1217 switch (m_format.type)
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;
1223 case TextureFormat::UNORM_SHORT_565:
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));
1230 case TextureFormat::UNSIGNED_SHORT_565:
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));
1237 case TextureFormat::UNORM_SHORT_555:
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));
1244 case TextureFormat::UNORM_SHORT_4444:
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));
1251 case TextureFormat::UNSIGNED_SHORT_4444:
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));
1258 case TextureFormat::UNORM_SHORT_5551:
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));
1265 case TextureFormat::UNORM_SHORT_1555:
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));
1272 case TextureFormat::UNSIGNED_SHORT_5551:
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));
1279 case TextureFormat::UNORM_INT_1010102_REV:
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);
1286 case TextureFormat::SNORM_INT_1010102_REV:
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);
1293 case TextureFormat::UNSIGNED_INT_1010102_REV:
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);
1300 case TextureFormat::SIGNED_INT_1010102_REV:
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);
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);
1311 case TextureFormat::UNSIGNED_INT_999_E5_REV:
1312 *((deUint32*)pixelPtr) = packRGB999E5(color);
1318 int numChannels = getNumUsedChannels(m_format.order);
1319 const TextureSwizzle::Channel* map = getChannelWriteSwizzle(m_format.order).components;
1320 int channelSize = getChannelSize(m_format.type);
1322 for (int c = 0; c < numChannels; c++)
1324 DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1325 floatToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1337 void PixelBufferAccess::setPixel (const IVec4& color, int x, int y, int z) const
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
1345 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1347 // Optimized fomats.
1348 if (m_format.type == TextureFormat::UNORM_INT8)
1350 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1352 writeRGBA8888Int(pixelPtr, color);
1355 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1357 writeRGB888Int(pixelPtr, color);
1362 #define PU(VAL, OFFS, BITS) (uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1363 #define PI(VAL, OFFS, BITS) (intToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1365 switch (m_format.type)
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;
1371 case TextureFormat::UNORM_SHORT_565:
1372 case TextureFormat::UNSIGNED_SHORT_565:
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));
1379 case TextureFormat::UNORM_SHORT_555:
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));
1386 case TextureFormat::UNORM_SHORT_4444:
1387 case TextureFormat::UNSIGNED_SHORT_4444:
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));
1394 case TextureFormat::UNORM_SHORT_5551:
1395 case TextureFormat::UNSIGNED_SHORT_5551:
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));
1402 case TextureFormat::UNORM_SHORT_1555:
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));
1409 case TextureFormat::UNORM_INT_1010102_REV:
1410 case TextureFormat::UNSIGNED_INT_1010102_REV:
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);
1417 case TextureFormat::SNORM_INT_1010102_REV:
1418 case TextureFormat::SIGNED_INT_1010102_REV:
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);
1428 int numChannels = getNumUsedChannels(m_format.order);
1429 const TextureSwizzle::Channel* map = getChannelWriteSwizzle(m_format.order).components;
1430 int channelSize = getChannelSize(m_format.type);
1432 for (int c = 0; c < numChannels; c++)
1434 DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1435 intToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1445 void PixelBufferAccess::setPixDepth (float depth, int x, int y, int z) const
1447 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1448 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1449 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1451 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1453 switch (m_format.type)
1455 case TextureFormat::UNSIGNED_INT_16_8_8:
1456 DE_ASSERT(m_format.order == TextureFormat::DS);
1457 writeUint32High16(pixelPtr, convertSatRte<deUint16>(depth * 65535.0f));
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));
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));
1470 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1471 DE_ASSERT(m_format.order == TextureFormat::DS);
1472 *((float*)pixelPtr) = depth;
1476 DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1477 floatToChannel(pixelPtr, depth, m_format.type);
1482 void PixelBufferAccess::setPixStencil (int stencil, int x, int y, int z) const
1484 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1485 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1486 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1488 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1490 switch (m_format.type)
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));
1498 case TextureFormat::UNSIGNED_INT_24_8_REV:
1499 DE_ASSERT(m_format.order == TextureFormat::DS);
1500 writeUint32High8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
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));
1509 DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1510 intToChannel(pixelPtr, stencil, m_format.type);
1515 static inline int imod (int a, int b)
1518 return m < 0 ? m + b : m;
1521 static inline int mirror (int a)
1523 return a >= 0.0f ? a : -(1 + a);
1526 // Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
1527 static inline float rint (float a)
1529 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
1531 float fracVal = deFloatFrac(a);
1533 if (fracVal != 0.5f)
1534 return deFloatRound(a); // Ordinary case.
1536 float floorVal = a - fracVal;
1537 bool roundUp = (deInt64)floorVal % 2 != 0;
1539 return floorVal + (roundUp ? 1.0f : 0.0f);
1542 static inline int wrap (Sampler::WrapMode mode, int c, int size)
1546 case tcu::Sampler::CLAMP_TO_BORDER:
1547 return deClamp32(c, -1, size);
1549 case tcu::Sampler::CLAMP_TO_EDGE:
1550 return deClamp32(c, 0, size-1);
1552 case tcu::Sampler::REPEAT_GL:
1553 return imod(c, size);
1555 case tcu::Sampler::REPEAT_CL:
1556 return imod(c, size);
1558 case tcu::Sampler::MIRRORED_ONCE:
1559 c = deClamp32(c, -size, size);
1562 case tcu::Sampler::MIRRORED_REPEAT_GL:
1563 return (size - 1) - mirror(imod(c, 2*size) - size);
1565 case tcu::Sampler::MIRRORED_REPEAT_CL:
1566 return deClamp32(c, 0, size-1); // \note Actual mirroring done already in unnormalization function.
1569 DE_ASSERT(DE_FALSE);
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)
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;
1586 case tcu::Sampler::REPEAT_CL:
1587 return (float)size * (c - deFloatFloor(c));
1589 case tcu::Sampler::MIRRORED_REPEAT_CL:
1590 return (float)size * deFloatAbs(c - 2.0f * rint(0.5f * c));
1593 DE_ASSERT(DE_FALSE);
1598 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
1600 DE_ASSERT(format.order == TextureFormat::D);
1602 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
1603 if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
1605 else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1614 // Texel lookup with color conversion.
1615 static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, int k)
1617 const TextureFormat& format = access.getFormat();
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));
1626 return sRGBToLinear(access.getPixel(i, j, k));
1630 return access.getPixel(i, j, k);
1634 // Border texel lookup with color conversion.
1635 static inline Vec4 lookupBorder (const tcu::TextureFormat& format, const tcu::Sampler& sampler)
1637 // "lookup" for a combined format does not make sense, disallow
1638 DE_ASSERT(!isCombinedDepthStencilType(format.type));
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;
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>();
1660 static inline float execCompare (const tcu::Vec4& color, Sampler::CompareMode compare, int chanNdx, float ref_, bool isFixedPoint)
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_);
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;
1681 return res ? 1.0f : 0.0f;
1684 static Vec4 sampleNearest1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1686 int width = access.getWidth();
1688 int x = deFloorFloatToInt32(u)+offset.x();
1690 // Check for CLAMP_TO_BORDER.
1691 if (sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))
1692 return lookupBorder(access.getFormat(), sampler);
1694 int i = wrap(sampler.wrapS, x, width);
1696 return lookup(access, i, offset.y(), 0);
1699 static Vec4 sampleNearest2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1701 int width = access.getWidth();
1702 int height = access.getHeight();
1704 int x = deFloorFloatToInt32(u)+offset.x();
1705 int y = deFloorFloatToInt32(v)+offset.y();
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);
1712 int i = wrap(sampler.wrapS, x, width);
1713 int j = wrap(sampler.wrapT, y, height);
1715 return lookup(access, i, j, offset.z());
1718 static Vec4 sampleNearest3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
1720 int width = access.getWidth();
1721 int height = access.getHeight();
1722 int depth = access.getDepth();
1724 int x = deFloorFloatToInt32(u)+offset.x();
1725 int y = deFloorFloatToInt32(v)+offset.y();
1726 int z = deFloorFloatToInt32(w)+offset.z();
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);
1734 int i = wrap(sampler.wrapS, x, width);
1735 int j = wrap(sampler.wrapT, y, height);
1736 int k = wrap(sampler.wrapR, z, depth);
1738 return lookup(access, i, j, k);
1741 static Vec4 sampleLinear1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1743 int w = access.getWidth();
1745 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1748 int i0 = wrap(sampler.wrapS, x0, w);
1749 int i1 = wrap(sampler.wrapS, x1, w);
1751 float a = deFloatFrac(u-0.5f);
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);
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);
1761 return p0 * (1.0f - a) + p1 * a;
1764 static Vec4 sampleLinear2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1766 int w = access.getWidth();
1767 int h = access.getHeight();
1769 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1771 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
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);
1779 float a = deFloatFrac(u-0.5f);
1780 float b = deFloatFrac(v-0.5f);
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);
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());
1794 return (p00*(1.0f-a)*(1.0f-b)) +
1795 (p10*( a)*(1.0f-b)) +
1796 (p01*(1.0f-a)*( b)) +
1800 static float sampleLinear1DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, const IVec2& offset, bool isFixedPointDepthFormat)
1802 int w = access.getWidth();
1804 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1807 int i0 = wrap(sampler.wrapS, x0, w);
1808 int i1 = wrap(sampler.wrapS, x1, w);
1810 float a = deFloatFrac(u-0.5f);
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);
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);
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);
1824 return (p0 * (1.0f - a)) + (p1 * a);
1827 static float sampleLinear2DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, float v, const IVec3& offset, bool isFixedPointDepthFormat)
1829 int w = access.getWidth();
1830 int h = access.getHeight();
1832 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1834 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
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);
1842 float a = deFloatFrac(u-0.5f);
1843 float b = deFloatFrac(v-0.5f);
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);
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());
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);
1863 return (p00*(1.0f-a)*(1.0f-b)) +
1864 (p10*( a)*(1.0f-b)) +
1865 (p01*(1.0f-a)*( b)) +
1869 static Vec4 sampleLinear3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
1871 int width = access.getWidth();
1872 int height = access.getHeight();
1873 int depth = access.getDepth();
1875 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1877 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
1879 int z0 = deFloorFloatToInt32(w-0.5f)+offset.z();
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);
1889 float a = deFloatFrac(u-0.5f);
1890 float b = deFloatFrac(v-0.5f);
1891 float c = deFloatFrac(w-0.5f);
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);
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);
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));
1921 Vec4 ConstPixelBufferAccess::sample1D (const Sampler& sampler, Sampler::FilterMode filter, float s, int level) const
1923 // check selected layer exists
1924 DE_ASSERT(de::inBounds(level, 0, m_size.y()));
1926 return sample1DOffset(sampler, filter, s, tcu::IVec2(0, level));
1929 Vec4 ConstPixelBufferAccess::sample2D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, int depth) const
1931 // check selected layer exists
1932 DE_ASSERT(de::inBounds(depth, 0, m_size.z()));
1934 return sample2DOffset(sampler, filter, s, t, tcu::IVec3(0, 0, depth));
1937 Vec4 ConstPixelBufferAccess::sample3D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r) const
1939 return sample3DOffset(sampler, filter, s, t, r, tcu::IVec3(0, 0, 0));
1942 Vec4 ConstPixelBufferAccess::sample1DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, const IVec2& offset) const
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()));
1948 // Non-normalized coordinates.
1951 if (sampler.normalizedCoords)
1952 u = unnormalize(sampler.wrapS, s, m_size.x());
1956 case Sampler::NEAREST: return sampleNearest1D (*this, sampler, u, offset);
1957 case Sampler::LINEAR: return sampleLinear1D (*this, sampler, u, offset);
1959 DE_ASSERT(DE_FALSE);
1964 Vec4 ConstPixelBufferAccess::sample2DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, const IVec3& offset) const
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()));
1970 // Non-normalized coordinates.
1974 if (sampler.normalizedCoords)
1976 u = unnormalize(sampler.wrapS, s, m_size.x());
1977 v = unnormalize(sampler.wrapT, t, m_size.y());
1982 case Sampler::NEAREST: return sampleNearest2D (*this, sampler, u, v, offset);
1983 case Sampler::LINEAR: return sampleLinear2D (*this, sampler, u, v, offset);
1985 DE_ASSERT(DE_FALSE);
1990 Vec4 ConstPixelBufferAccess::sample3DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r, const IVec3& offset) const
1992 // Non-normalized coordinates.
1997 if (sampler.normalizedCoords)
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());
2006 case Sampler::NEAREST: return sampleNearest3D (*this, sampler, u, v, w, offset);
2007 case Sampler::LINEAR: return sampleLinear3D (*this, sampler, u, v, w, offset);
2009 DE_ASSERT(DE_FALSE);
2014 float ConstPixelBufferAccess::sample1DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, const IVec2& offset) const
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()));
2020 // Format information for comparison function
2021 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2023 // Non-normalized coordinates.
2026 if (sampler.normalizedCoords)
2027 u = unnormalize(sampler.wrapS, s, m_size.x());
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);
2034 DE_ASSERT(DE_FALSE);
2039 float ConstPixelBufferAccess::sample2DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, float t, const IVec3& offset) const
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()));
2045 // Format information for comparison function
2046 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2048 // Non-normalized coordinates.
2052 if (sampler.normalizedCoords)
2054 u = unnormalize(sampler.wrapS, s, m_size.x());
2055 v = unnormalize(sampler.wrapT, t, m_size.y());
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);
2063 DE_ASSERT(DE_FALSE);
2068 TextureLevel::TextureLevel (void)
2074 TextureLevel::TextureLevel (const TextureFormat& format)
2080 TextureLevel::TextureLevel (const TextureFormat& format, int width, int height, int depth)
2084 setSize(width, height, depth);
2087 TextureLevel::~TextureLevel (void)
2091 void TextureLevel::setStorage (const TextureFormat& format, int width, int height, int depth)
2094 setSize(width, height, depth);
2097 void TextureLevel::setSize (int width, int height, int depth)
2099 int pixelSize = m_format.getPixelSize();
2101 m_size = IVec3(width, height, depth);
2103 m_data.setStorage(m_size.x() * m_size.y() * m_size.z() * pixelSize);
2106 Vec4 sampleLevelArray1D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, int depth, float lod)
2108 return sampleLevelArray1DOffset(levels, numLevels, sampler, s, lod, IVec2(0, depth)); // y-offset in 1D textures is layer selector
2111 Vec4 sampleLevelArray2D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, int depth, float lod)
2113 return sampleLevelArray2DOffset(levels, numLevels, sampler, s, t, lod, IVec3(0, 0, depth)); // z-offset in 2D textures is layer selector
2116 Vec4 sampleLevelArray3D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod)
2118 return sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, IVec3(0, 0, 0));
2121 Vec4 sampleLevelArray1DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float lod, const IVec2& offset)
2123 bool magnified = lod <= sampler.lodThreshold;
2124 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2128 case Sampler::NEAREST: return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2129 case Sampler::LINEAR: return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2131 case Sampler::NEAREST_MIPMAP_NEAREST:
2132 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2138 return levels[level].sample1DOffset(sampler, levelFilter, s, offset);
2141 case Sampler::NEAREST_MIPMAP_LINEAR:
2142 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2152 return t0*(1.0f - f) + t1*f;
2156 DE_ASSERT(DE_FALSE);
2161 Vec4 sampleLevelArray2DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float lod, const IVec3& offset)
2163 bool magnified = lod <= sampler.lodThreshold;
2164 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
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);
2171 case Sampler::NEAREST_MIPMAP_NEAREST:
2172 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2178 return levels[level].sample2DOffset(sampler, levelFilter, s, t, offset);
2181 case Sampler::NEAREST_MIPMAP_LINEAR:
2182 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2192 return t0*(1.0f - f) + t1*f;
2196 DE_ASSERT(DE_FALSE);
2201 Vec4 sampleLevelArray3DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod, const IVec3& offset)
2203 bool magnified = lod <= sampler.lodThreshold;
2204 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
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);
2211 case Sampler::NEAREST_MIPMAP_NEAREST:
2212 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2218 return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2221 case Sampler::NEAREST_MIPMAP_LINEAR:
2222 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2232 return t0*(1.0f - f) + t1*f;
2236 DE_ASSERT(DE_FALSE);
2241 float sampleLevelArray1DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float lod, const IVec2& offset)
2243 bool magnified = lod <= sampler.lodThreshold;
2244 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
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);
2251 case Sampler::NEAREST_MIPMAP_NEAREST:
2252 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2258 return levels[level].sample1DCompare(sampler, levelFilter, ref, s, offset);
2261 case Sampler::NEAREST_MIPMAP_LINEAR:
2262 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2272 return t0*(1.0f - f) + t1*f;
2276 DE_ASSERT(DE_FALSE);
2281 float sampleLevelArray2DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float t, float lod, const IVec3& offset)
2283 bool magnified = lod <= sampler.lodThreshold;
2284 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
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);
2291 case Sampler::NEAREST_MIPMAP_NEAREST:
2292 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2298 return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2301 case Sampler::NEAREST_MIPMAP_LINEAR:
2302 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2312 return t0*(1.0f - f) + t1*f;
2316 DE_ASSERT(DE_FALSE);
2321 static Vec4 fetchGatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2323 DE_ASSERT(de::inBounds(componentNdx, 0, 4));
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);
2334 for (int i = 0; i < 4; i++)
2336 const int sampleX = wrap(sampler.wrapS, x0 + offsets[i].x(), w);
2337 const int sampleY = wrap(sampler.wrapT, y0 + offsets[i].y(), h);
2340 if (deInBounds32(sampleX, 0, w) && deInBounds32(sampleY, 0, h))
2341 pixel = lookup(src, sampleX, sampleY, depth);
2343 pixel = lookupBorder(src.getFormat(), sampler);
2345 result[i] = pixel[componentNdx];
2351 Vec4 gatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2353 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
2354 DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2356 return fetchGatherArray2DOffsets(src, sampler, s, t, depth, componentNdx, offsets);
2359 Vec4 gatherArray2DOffsetsCompare (const ConstPixelBufferAccess& src, const Sampler& sampler, float ref, float s, float t, int depth, const IVec2 (&offsets)[4])
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);
2365 const bool isFixedPoint = isFixedPointDepthTextureFormat(src.getFormat());
2366 const Vec4 gathered = fetchGatherArray2DOffsets(src, sampler, s, t, depth, 0 /* component 0: depth */, offsets);
2369 for (int i = 0; i < 4; i++)
2370 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
2375 static Vec4 sampleCubeSeamlessNearest (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float s, float t, int depth)
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);
2383 CubeFace selectCubeFace (const Vec3& coords)
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);
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;
2400 // Some of the components are equal. Use tie-breaking rule.
2404 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2406 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2411 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2413 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2418 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2420 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2423 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2427 Vec2 projectToFace (CubeFace face, const Vec3& coord)
2429 const float rx = coord.x();
2430 const float ry = coord.y();
2431 const float rz = coord.z();
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;
2447 DE_ASSERT(DE_FALSE);
2451 s = ((sc / ma) + 1.0f) / 2.0f;
2452 t = ((tc / ma) + 1.0f) / 2.0f;
2457 CubeFaceFloatCoords getCubeFaceCoords (const Vec3& coords)
2459 const CubeFace face = selectCubeFace(coords);
2460 return CubeFaceFloatCoords(face, projectToFace(face, coords));
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)
2467 bool uInBounds = de::inBounds(origCoords.s, 0, size);
2468 bool vInBounds = de::inBounds(origCoords.t, 0, size);
2470 if (uInBounds && vInBounds)
2473 if (!uInBounds && !vInBounds)
2474 return CubeFaceIntCoords(CUBEFACE_LAST, -1, -1);
2476 IVec2 coords(wrap(Sampler::CLAMP_TO_BORDER, origCoords.s, size),
2477 wrap(Sampler::CLAMP_TO_BORDER, origCoords.t, size));
2478 IVec3 canonizedCoords;
2480 // Map the uv coordinates to canonized 3d coordinates.
2482 switch (origCoords.face)
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);
2493 // Find an appropriate face to re-map the coordinates to.
2495 if (canonizedCoords.x() == -1)
2496 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_X, IVec2(canonizedCoords.z(), size-1-canonizedCoords.y()));
2498 if (canonizedCoords.x() == size)
2499 return CubeFaceIntCoords(CUBEFACE_POSITIVE_X, IVec2(size-1-canonizedCoords.z(), size-1-canonizedCoords.y()));
2501 if (canonizedCoords.y() == -1)
2502 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Y, IVec2(canonizedCoords.x(), size-1-canonizedCoords.z()));
2504 if (canonizedCoords.y() == size)
2505 return CubeFaceIntCoords(CUBEFACE_POSITIVE_Y, IVec2(canonizedCoords.x(), canonizedCoords.z()));
2507 if (canonizedCoords.z() == -1)
2508 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Z, IVec2(size-1-canonizedCoords.x(), size-1-canonizedCoords.y()));
2510 if (canonizedCoords.z() == size)
2511 return CubeFaceIntCoords(CUBEFACE_POSITIVE_Z, IVec2(canonizedCoords.x(), size-1-canonizedCoords.y()));
2514 return CubeFaceIntCoords(CUBEFACE_LAST, IVec2(-1));
2517 static void getCubeLinearSamples (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, float u, float v, int depth, Vec4 (&dst)[4])
2519 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2520 int size = faceAccesses[0].getWidth();
2521 int x0 = deFloorFloatToInt32(u-0.5f);
2523 int y0 = deFloorFloatToInt32(v-0.5f);
2525 IVec2 baseSampleCoords[4] =
2532 Vec4 sampleColors[4];
2533 bool hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
2535 // Find correct faces and coordinates for out-of-bounds sample coordinates.
2537 for (int i = 0; i < 4; i++)
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);
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.
2551 int bothOutOfBoundsNdx = -1;
2552 for (int i = 0; i < 4; i++)
2554 if (hasBothCoordsOutOfBounds[i])
2556 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
2557 bothOutOfBoundsNdx = i;
2560 if (bothOutOfBoundsNdx != -1)
2562 sampleColors[bothOutOfBoundsNdx] = Vec4(0.0f);
2563 for (int i = 0; i < 4; i++)
2564 if (i != bothOutOfBoundsNdx)
2565 sampleColors[bothOutOfBoundsNdx] += sampleColors[i];
2567 sampleColors[bothOutOfBoundsNdx] = sampleColors[bothOutOfBoundsNdx] * (1.0f/3.0f);
2571 for (int i = 0; i < DE_LENGTH_OF_ARRAY(sampleColors); i++)
2572 dst[i] = sampleColors[i];
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)
2578 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2580 int size = faceAccesses[0].getWidth();
2581 // Non-normalized coordinates.
2585 if (sampler.normalizedCoords)
2587 u = unnormalize(sampler.wrapS, s, size);
2588 v = unnormalize(sampler.wrapT, t, size);
2591 // Get sample colors.
2593 Vec4 sampleColors[4];
2594 getCubeLinearSamples(faceAccesses, baseFace, u, v, depth, sampleColors);
2598 float a = deFloatFrac(u-0.5f);
2599 float b = deFloatFrac(v-0.5f);
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));
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)
2609 bool magnified = lod <= sampler.lodThreshold;
2610 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2614 case Sampler::NEAREST:
2615 return sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth);
2617 case Sampler::LINEAR:
2619 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2620 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2621 faceAccesses[i] = faces[i][0];
2623 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
2626 case Sampler::NEAREST_MIPMAP_NEAREST:
2627 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2633 if (levelFilter == Sampler::NEAREST)
2634 return sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
2637 DE_ASSERT(levelFilter == Sampler::LINEAR);
2639 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2640 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2641 faceAccesses[i] = faces[i][level];
2643 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
2647 case Sampler::NEAREST_MIPMAP_LINEAR:
2648 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2658 if (levelFilter == Sampler::NEAREST)
2660 t0 = sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
2661 t1 = sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
2665 DE_ASSERT(levelFilter == Sampler::LINEAR);
2667 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
2668 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
2669 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2671 faceAccesses0[i] = faces[i][level0];
2672 faceAccesses1[i] = faces[i][level1];
2675 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
2676 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
2679 return t0*(1.0f - f) + t1*f;
2683 DE_ASSERT(DE_FALSE);
2688 static float sampleCubeSeamlessNearestCompare (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float ref, float s, float t, int depth = 0)
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));
2696 static float sampleCubeSeamlessLinearCompare (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float ref, float s, float t)
2698 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2700 int size = faceAccesses[0].getWidth();
2701 // Non-normalized coordinates.
2705 if (sampler.normalizedCoords)
2707 u = unnormalize(sampler.wrapS, s, size);
2708 v = unnormalize(sampler.wrapT, t, size);
2711 int x0 = deFloorFloatToInt32(u-0.5f);
2713 int y0 = deFloorFloatToInt32(v-0.5f);
2715 IVec2 baseSampleCoords[4] =
2723 bool hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
2725 // Find correct faces and coordinates for out-of-bounds sample coordinates.
2727 for (int i = 0; i < 4; i++)
2729 CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
2730 hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
2732 if (!hasBothCoordsOutOfBounds[i])
2734 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
2736 sampleRes[i] = execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
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.
2746 int bothOutOfBoundsNdx = -1;
2747 for (int i = 0; i < 4; i++)
2749 if (hasBothCoordsOutOfBounds[i])
2751 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
2752 bothOutOfBoundsNdx = i;
2755 if (bothOutOfBoundsNdx != -1)
2757 sampleRes[bothOutOfBoundsNdx] = 0.0f;
2758 for (int i = 0; i < 4; i++)
2759 if (i != bothOutOfBoundsNdx)
2760 sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
2762 sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0f/3.0f);
2768 float a = deFloatFrac(u-0.5f);
2769 float b = deFloatFrac(v-0.5f);
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));
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)
2779 bool magnified = lod <= sampler.lodThreshold;
2780 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2784 case Sampler::NEAREST:
2785 return sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
2787 case Sampler::LINEAR:
2789 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2790 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2791 faceAccesses[i] = faces[i][0];
2793 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
2796 case Sampler::NEAREST_MIPMAP_NEAREST:
2797 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2803 if (levelFilter == Sampler::NEAREST)
2804 return sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
2807 DE_ASSERT(levelFilter == Sampler::LINEAR);
2809 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2810 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2811 faceAccesses[i] = faces[i][level];
2813 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
2817 case Sampler::NEAREST_MIPMAP_LINEAR:
2818 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2828 if (levelFilter == Sampler::NEAREST)
2830 t0 = sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
2831 t1 = sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
2835 DE_ASSERT(levelFilter == Sampler::LINEAR);
2837 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
2838 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
2839 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2841 faceAccesses0[i] = faces[i][level0];
2842 faceAccesses1[i] = faces[i][level1];
2845 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
2846 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
2849 return t0*(1.0f - f) + t1*f;
2853 DE_ASSERT(DE_FALSE);
2858 // Cube map array sampling
2860 static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face)
2862 const ConstPixelBufferAccess& level = levels[levelNdx];
2863 const int depth = (slice * 6) + getCubeArrayFaceIndex(face);
2865 return getSubregion(level, 0, 0, depth, level.getWidth(), level.getHeight(), 1);
2868 static Vec4 sampleCubeArraySeamless (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float s, float t, float lod)
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;
2876 case Sampler::NEAREST:
2877 return sampleCubeSeamlessNearest(levels[0], sampler, s, t, faceDepth);
2879 case Sampler::LINEAR:
2881 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2882 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2883 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
2885 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
2888 case Sampler::NEAREST_MIPMAP_NEAREST:
2889 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2895 if (levelFilter == Sampler::NEAREST)
2896 return sampleCubeSeamlessNearest(levels[level], sampler, s, t, faceDepth);
2899 DE_ASSERT(levelFilter == Sampler::LINEAR);
2901 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2902 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2903 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
2905 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
2909 case Sampler::NEAREST_MIPMAP_LINEAR:
2910 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
2920 if (levelFilter == Sampler::NEAREST)
2922 t0 = sampleCubeSeamlessNearest(levels[level0], sampler, s, t, faceDepth);
2923 t1 = sampleCubeSeamlessNearest(levels[level1], sampler, s, t, faceDepth);
2927 DE_ASSERT(levelFilter == Sampler::LINEAR);
2929 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
2930 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
2931 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2933 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
2934 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
2937 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, 0);
2938 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, 0);
2941 return t0*(1.0f - f) + t1*f;
2945 DE_ASSERT(DE_FALSE);
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)
2952 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face);
2953 const bool magnified = lod <= sampler.lodThreshold;
2954 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2958 case Sampler::NEAREST:
2959 return sampleCubeSeamlessNearestCompare(levels[0], sampler, ref, s, t, faceDepth);
2961 case Sampler::LINEAR:
2963 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2964 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2965 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
2967 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
2970 case Sampler::NEAREST_MIPMAP_NEAREST:
2971 case Sampler::LINEAR_MIPMAP_NEAREST:
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;
2977 if (levelFilter == Sampler::NEAREST)
2978 return sampleCubeSeamlessNearestCompare(levels[level], sampler, ref, s, t, faceDepth);
2981 DE_ASSERT(levelFilter == Sampler::LINEAR);
2983 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2984 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2985 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
2987 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
2991 case Sampler::NEAREST_MIPMAP_LINEAR:
2992 case Sampler::LINEAR_MIPMAP_LINEAR:
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);
3002 if (levelFilter == Sampler::NEAREST)
3004 t0 = sampleCubeSeamlessNearestCompare(levels[level0], sampler, ref, s, t, faceDepth);
3005 t1 = sampleCubeSeamlessNearestCompare(levels[level1], sampler, ref, s, t, faceDepth);
3009 DE_ASSERT(levelFilter == Sampler::LINEAR);
3011 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3012 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3013 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3015 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
3016 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
3019 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
3020 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
3023 return t0*(1.0f - f) + t1*f;
3027 DE_ASSERT(DE_FALSE);
3032 inline int computeMipPyramidLevels (int size)
3034 return deLog2Floor32(size)+1;
3037 inline int computeMipPyramidLevels (int width, int height)
3039 return deLog2Floor32(de::max(width, height))+1;
3042 inline int computeMipPyramidLevels (int width, int height, int depth)
3044 return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
3047 inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx)
3049 return de::max(baseLevelSize >> levelNdx, 1);
3052 // TextureLevelPyramid
3054 TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels)
3056 , m_data (numLevels)
3057 , m_access (numLevels)
3061 TextureLevelPyramid::TextureLevelPyramid (const TextureLevelPyramid& other)
3062 : m_format (other.m_format)
3063 , m_data (other.getNumLevels())
3064 , m_access (other.getNumLevels())
3066 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3068 if (!other.isLevelEmpty(levelNdx))
3070 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
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());
3078 TextureLevelPyramid& TextureLevelPyramid::operator= (const TextureLevelPyramid& other)
3083 m_format = other.m_format;
3084 m_data.resize(other.getNumLevels());
3085 m_access.resize(other.getNumLevels());
3087 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3089 if (!other.isLevelEmpty(levelNdx))
3091 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
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());
3096 else if (!isLevelEmpty(levelNdx))
3097 clearLevel(levelNdx);
3103 TextureLevelPyramid::~TextureLevelPyramid (void)
3107 void TextureLevelPyramid::allocLevel (int levelNdx, int width, int height, int depth)
3109 const int size = m_format.getPixelSize()*width*height*depth;
3111 DE_ASSERT(isLevelEmpty(levelNdx));
3113 m_data[levelNdx].setStorage(size);
3114 m_access[levelNdx] = PixelBufferAccess(m_format, width, height, depth, m_data[levelNdx].getPtr());
3117 void TextureLevelPyramid::clearLevel (int levelNdx)
3119 DE_ASSERT(!isLevelEmpty(levelNdx));
3121 m_data[levelNdx].clear();
3122 m_access[levelNdx] = PixelBufferAccess();
3127 Texture1D::Texture1D (const TextureFormat& format, int width)
3128 : TextureLevelPyramid (format, computeMipPyramidLevels(width))
3130 , m_view (getNumLevels(), getLevels())
3134 Texture1D::Texture1D (const Texture1D& other)
3135 : TextureLevelPyramid (other)
3136 , m_width (other.m_width)
3137 , m_view (getNumLevels(), getLevels())
3141 Texture1D& Texture1D::operator= (const Texture1D& other)
3146 TextureLevelPyramid::operator=(other);
3148 m_width = other.m_width;
3149 m_view = Texture1DView(getNumLevels(), getLevels());
3154 Texture1D::~Texture1D (void)
3158 void Texture1D::allocLevel (int levelNdx)
3160 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3162 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3164 TextureLevelPyramid::allocLevel(levelNdx, width, 1, 1);
3169 Texture2D::Texture2D (const TextureFormat& format, int width, int height)
3170 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height))
3173 , m_view (getNumLevels(), getLevels())
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())
3185 Texture2D& Texture2D::operator= (const Texture2D& other)
3190 TextureLevelPyramid::operator=(other);
3192 m_width = other.m_width;
3193 m_height = other.m_height;
3194 m_view = Texture2DView(getNumLevels(), getLevels());
3199 Texture2D::~Texture2D (void)
3203 void Texture2D::allocLevel (int levelNdx)
3205 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3207 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3208 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3210 TextureLevelPyramid::allocLevel(levelNdx, width, height, 1);
3215 TextureCubeView::TextureCubeView (void)
3218 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3219 m_levels[ndx] = DE_NULL;
3222 TextureCubeView::TextureCubeView (int numLevels, const ConstPixelBufferAccess* const (&levels) [CUBEFACE_LAST])
3223 : m_numLevels(numLevels)
3225 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3226 m_levels[ndx] = levels[ndx];
3229 tcu::Vec4 TextureCubeView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3231 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
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);
3238 return sampleLevelArray2D(m_levels[coords.face], m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod);
3241 float TextureCubeView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3243 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
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);
3250 return sampleLevelArray2DCompare(m_levels[coords.face], m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, 0));
3253 Vec4 TextureCubeView::gather (const Sampler& sampler, float s, float t, float r, int componentNdx) const
3255 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3257 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3258 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3259 faceAccesses[i] = m_levels[i][0];
3261 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3262 const int size = faceAccesses[0].getWidth();
3263 // Non-normalized coordinates.
3267 if (sampler.normalizedCoords)
3269 u = unnormalize(sampler.wrapS, coords.s, size);
3270 v = unnormalize(sampler.wrapT, coords.t, size);
3273 Vec4 sampleColors[4];
3274 getCubeLinearSamples(faceAccesses, coords.face, u, v, 0, sampleColors);
3276 const int sampleIndices[4] = { 2, 3, 1, 0 }; // \note Gather returns the samples in a non-obvious order.
3278 for (int i = 0; i < 4; i++)
3279 result[i] = sampleColors[sampleIndices[i]][componentNdx];
3284 Vec4 TextureCubeView::gatherCompare (const Sampler& sampler, float ref, float s, float t, float r) const
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);
3290 Sampler noCompareSampler = sampler;
3291 noCompareSampler.compare = Sampler::COMPAREMODE_NONE;
3293 const Vec4 gathered = gather(noCompareSampler, s, t, r, 0 /* component 0: depth */);
3294 const bool isFixedPoint = isFixedPointDepthTextureFormat(m_levels[0][0].getFormat());
3296 for (int i = 0; i < 4; i++)
3297 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
3304 TextureCube::TextureCube (const TextureFormat& format, int size)
3308 const int numLevels = computeMipPyramidLevels(m_size);
3309 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3311 for (int face = 0; face < CUBEFACE_LAST; face++)
3313 m_data[face].resize(numLevels);
3314 m_access[face].resize(numLevels);
3315 levels[face] = &m_access[face][0];
3318 m_view = TextureCubeView(numLevels, levels);
3321 TextureCube::TextureCube (const TextureCube& other)
3322 : m_format (other.m_format)
3323 , m_size (other.m_size)
3325 const int numLevels = computeMipPyramidLevels(m_size);
3326 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3328 for (int face = 0; face < CUBEFACE_LAST; face++)
3330 m_data[face].resize(numLevels);
3331 m_access[face].resize(numLevels);
3332 levels[face] = &m_access[face][0];
3335 m_view = TextureCubeView(numLevels, levels);
3337 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3339 for (int face = 0; face < CUBEFACE_LAST; face++)
3341 if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3343 allocLevel((CubeFace)face, levelNdx);
3344 copy(getLevelFace(levelNdx, (CubeFace)face),
3345 other.getLevelFace(levelNdx, (CubeFace)face));
3351 TextureCube& TextureCube::operator= (const TextureCube& other)
3356 const int numLevels = computeMipPyramidLevels(other.m_size);
3357 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3359 for (int face = 0; face < CUBEFACE_LAST; face++)
3361 m_data[face].resize(numLevels);
3362 m_access[face].resize(numLevels);
3363 levels[face] = &m_access[face][0];
3366 m_format = other.m_format;
3367 m_size = other.m_size;
3368 m_view = TextureCubeView(numLevels, levels);
3370 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3372 for (int face = 0; face < CUBEFACE_LAST; face++)
3374 if (!isLevelEmpty((CubeFace)face, levelNdx))
3375 clearLevel((CubeFace)face, levelNdx);
3377 if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3379 allocLevel((CubeFace)face, levelNdx);
3380 copy(getLevelFace(levelNdx, (CubeFace)face),
3381 other.getLevelFace(levelNdx, (CubeFace)face));
3389 TextureCube::~TextureCube (void)
3393 void TextureCube::allocLevel (tcu::CubeFace face, int levelNdx)
3395 const int size = getMipPyramidLevelSize(m_size, levelNdx);
3396 const int dataSize = m_format.getPixelSize()*size*size;
3397 DE_ASSERT(isLevelEmpty(face, levelNdx));
3399 m_data[face][levelNdx].setStorage(dataSize);
3400 m_access[face][levelNdx] = PixelBufferAccess(m_format, size, size, 1, m_data[face][levelNdx].getPtr());
3403 void TextureCube::clearLevel (tcu::CubeFace face, int levelNdx)
3405 DE_ASSERT(!isLevelEmpty(face, levelNdx));
3406 m_data[face][levelNdx].clear();
3407 m_access[face][levelNdx] = PixelBufferAccess();
3410 // Texture1DArrayView
3412 Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3413 : m_numLevels (numLevels)
3418 inline int Texture1DArrayView::selectLayer (float r) const
3420 DE_ASSERT(m_numLevels > 0 && m_levels);
3421 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getHeight()-1);
3424 Vec4 Texture1DArrayView::sample (const Sampler& sampler, float s, float t, float lod) const
3426 return sampleLevelArray1D(m_levels, m_numLevels, sampler, s, selectLayer(t), lod);
3429 Vec4 Texture1DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float lod, deInt32 offset) const
3431 return sampleLevelArray1DOffset(m_levels, m_numLevels, sampler, s, lod, IVec2(offset, selectLayer(t)));
3434 float Texture1DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float lod) const
3436 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(0, selectLayer(t)));
3439 float Texture1DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float lod, deInt32 offset) const
3441 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(offset, selectLayer(t)));
3444 // Texture2DArrayView
3446 Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3447 : m_numLevels (numLevels)
3452 inline int Texture2DArrayView::selectLayer (float r) const
3454 DE_ASSERT(m_numLevels > 0 && m_levels);
3455 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getDepth()-1);
3458 Vec4 Texture2DArrayView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3460 return sampleLevelArray2D(m_levels, m_numLevels, sampler, s, t, selectLayer(r), lod);
3463 float Texture2DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3465 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(0, 0, selectLayer(r)));
3468 Vec4 Texture2DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float r, float lod, const IVec2& offset) const
3470 return sampleLevelArray2DOffset(m_levels, m_numLevels, sampler, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
3473 float Texture2DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float r, float lod, const IVec2& offset) const
3475 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
3478 Vec4 Texture2DArrayView::gatherOffsets (const Sampler& sampler, float s, float t, float r, int componentNdx, const IVec2 (&offsets)[4]) const
3480 return gatherArray2DOffsets(m_levels[0], sampler, s, t, selectLayer(r), componentNdx, offsets);
3483 Vec4 Texture2DArrayView::gatherOffsetsCompare (const Sampler& sampler, float ref, float s, float t, float r, const IVec2 (&offsets)[4]) const
3485 return gatherArray2DOffsetsCompare(m_levels[0], sampler, ref, s, t, selectLayer(r), offsets);
3490 Texture1DArray::Texture1DArray (const TextureFormat& format, int width, int numLayers)
3491 : TextureLevelPyramid (format, computeMipPyramidLevels(width))
3493 , m_numLayers (numLayers)
3494 , m_view (getNumLevels(), getLevels())
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())
3506 Texture1DArray& Texture1DArray::operator= (const Texture1DArray& other)
3511 TextureLevelPyramid::operator=(other);
3513 m_width = other.m_width;
3514 m_numLayers = other.m_numLayers;
3515 m_view = Texture1DArrayView(getNumLevels(), getLevels());
3520 Texture1DArray::~Texture1DArray (void)
3524 void Texture1DArray::allocLevel (int levelNdx)
3526 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3528 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3530 TextureLevelPyramid::allocLevel(levelNdx, width, m_numLayers, 1);
3535 Texture2DArray::Texture2DArray (const TextureFormat& format, int width, int height, int numLayers)
3536 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height))
3539 , m_numLayers (numLayers)
3540 , m_view (getNumLevels(), getLevels())
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())
3553 Texture2DArray& Texture2DArray::operator= (const Texture2DArray& other)
3558 TextureLevelPyramid::operator=(other);
3560 m_width = other.m_width;
3561 m_height = other.m_height;
3562 m_numLayers = other.m_numLayers;
3563 m_view = Texture2DArrayView(getNumLevels(), getLevels());
3568 Texture2DArray::~Texture2DArray (void)
3572 void Texture2DArray::allocLevel (int levelNdx)
3574 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3576 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3577 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3579 TextureLevelPyramid::allocLevel(levelNdx, width, height, m_numLayers);
3584 Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels)
3585 : m_numLevels (numLevels)
3592 Texture3D::Texture3D (const TextureFormat& format, int width, int height, int depth)
3593 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height, depth))
3597 , m_view (getNumLevels(), getLevels())
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())
3610 Texture3D& Texture3D::operator= (const Texture3D& other)
3615 TextureLevelPyramid::operator=(other);
3617 m_width = other.m_width;
3618 m_height = other.m_height;
3619 m_depth = other.m_depth;
3620 m_view = Texture3DView(getNumLevels(), getLevels());
3625 Texture3D::~Texture3D (void)
3629 void Texture3D::allocLevel (int levelNdx)
3631 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3633 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3634 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3635 const int depth = getMipPyramidLevelSize(m_depth, levelNdx);
3637 TextureLevelPyramid::allocLevel(levelNdx, width, height, depth);
3640 // TextureCubeArrayView
3642 TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3643 : m_numLevels (numLevels)
3648 inline int TextureCubeArrayView::selectLayer (float q) const
3650 DE_ASSERT(m_numLevels > 0 && m_levels);
3651 DE_ASSERT((m_levels[0].getDepth() % 6) == 0);
3653 return de::clamp(deFloorFloatToInt32(q + 0.5f), 0, (m_levels[0].getDepth() / 6)-1);
3656 tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const
3658 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3659 const int layer = selectLayer(q);
3660 const int faceDepth = (layer * 6) + getCubeArrayFaceIndex(coords.face);
3662 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3664 if (sampler.seamlessCubeMap)
3665 return sampleCubeArraySeamless(m_levels, m_numLevels, layer, coords.face, sampler, coords.s, coords.t, lod);
3667 return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod);
3670 float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const
3672 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3673 const int layer = selectLayer(q);
3674 const int faceDepth = (layer * 6) + getCubeArrayFaceIndex(coords.face);
3676 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3678 if (sampler.seamlessCubeMap)
3679 return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, layer, coords.face, sampler, ref, coords.s, coords.t, lod);
3681 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth));
3686 TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int depth)
3687 : TextureLevelPyramid (format, computeMipPyramidLevels(size))
3690 , m_view (getNumLevels(), getLevels())
3692 DE_ASSERT(m_depth % 6 == 0);
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())
3701 DE_ASSERT(m_depth % 6 == 0);
3704 TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
3709 TextureLevelPyramid::operator=(other);
3711 m_size = other.m_size;
3712 m_depth = other.m_depth;
3713 m_view = TextureCubeArrayView(getNumLevels(), getLevels());
3715 DE_ASSERT(m_depth % 6 == 0);
3720 TextureCubeArray::~TextureCubeArray (void)
3724 void TextureCubeArray::allocLevel (int levelNdx)
3726 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3728 const int size = getMipPyramidLevelSize(m_size, levelNdx);
3730 TextureLevelPyramid::allocLevel(levelNdx, size, size, m_depth);
3733 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order)
3735 const char* const orderStrings[] =
3762 return str << de::getSizedArrayElement<TextureFormat::CHANNELORDER_LAST>(orderStrings, order);
3765 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelType type)
3767 const char* const typeStrings[] =
3783 "SNORM_INT_1010102_REV",
3784 "UNORM_INT_1010102_REV",
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",
3806 "FLOAT_UNSIGNED_INT_24_8_REV"
3809 return str << de::getSizedArrayElement<TextureFormat::CHANNELTYPE_LAST>(typeStrings, type);
3812 std::ostream& operator<< (std::ostream& str, CubeFace face)
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 << ")";
3827 std::ostream& operator<< (std::ostream& str, TextureFormat format)
3829 return str << format.order << ", " << format.type << "";
3832 std::ostream& operator<< (std::ostream& str, const ConstPixelBufferAccess& access)
3834 return str << "format = (" << access.getFormat() << "), size = "
3835 << access.getWidth() << " x " << access.getHeight() << " x " << access.getDepth()
3836 << ", pitch = " << access.getRowPitch() << " / " << access.getSlicePitch();