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 inline deUint16 convertSatRteUint10 (float f)
262 const deUint16 rounded = convertSatRte<deUint16>(f);
263 const deUint16 maxUint10 = 0x3FFu;
264 return de::min(rounded, maxUint10);
267 inline deUint16 convertSatRteUint12 (float f)
269 const deUint16 rounded = convertSatRte<deUint16>(f);
270 const deUint16 maxUint12 = 0xFFFu;
271 return de::min(rounded, maxUint12);
274 inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
276 // make sure this table is updated if format table is updated
277 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
281 case TextureFormat::SNORM_INT8: return de::max(-1.0f, (float)*((const deInt8*)value) / 127.0f);
282 case TextureFormat::SNORM_INT16: return de::max(-1.0f, (float)*((const deInt16*)value) / 32767.0f);
283 case TextureFormat::SNORM_INT32: return de::max(-1.0f, (float)*((const deInt32*)value) / 2147483647.0f);
284 case TextureFormat::UNORM_INT8: return (float)*((const deUint8*)value) / 255.0f;
285 case TextureFormat::UNORM_INT16: return (float)*((const deUint16*)value) / 65535.0f;
286 case TextureFormat::UNORM_INT24: return (float)readUint24(value) / 16777215.0f;
287 case TextureFormat::UNORM_INT32: return (float)*((const deUint32*)value) / 4294967295.0f;
288 case TextureFormat::SIGNED_INT8: return (float)*((const deInt8*)value);
289 case TextureFormat::SIGNED_INT16: return (float)*((const deInt16*)value);
290 case TextureFormat::SIGNED_INT32: return (float)*((const deInt32*)value);
291 case TextureFormat::UNSIGNED_INT8: return (float)*((const deUint8*)value);
292 case TextureFormat::UNSIGNED_INT16: return (float)*((const deUint16*)value);
293 case TextureFormat::UNSIGNED_INT24: return (float)readUint24(value);
294 case TextureFormat::UNSIGNED_INT32: return (float)*((const deUint32*)value);
295 case TextureFormat::HALF_FLOAT: return deFloat16To32(*(const deFloat16*)value);
296 case TextureFormat::FLOAT: return *((const float*)value);
297 case TextureFormat::FLOAT64: return (float)*((const double*)value);
298 case TextureFormat::UNORM_SHORT_10: return (float)((*((const deUint16*)value)) >> 6u) / 1023.0f;
299 case TextureFormat::UNORM_SHORT_12: return (float)((*((const deUint16*)value)) >> 4u) / 4095.0f;
306 inline int channelToInt (const deUint8* value, TextureFormat::ChannelType type)
308 // make sure this table is updated if format table is updated
309 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
313 case TextureFormat::SNORM_INT8: return (int)*((const deInt8*)value);
314 case TextureFormat::SNORM_INT16: return (int)*((const deInt16*)value);
315 case TextureFormat::SNORM_INT32: return (int)*((const deInt32*)value);
316 case TextureFormat::UNORM_INT8: return (int)*((const deUint8*)value);
317 case TextureFormat::UNORM_INT16: return (int)*((const deUint16*)value);
318 case TextureFormat::UNORM_INT24: return (int)readUint24(value);
319 case TextureFormat::UNORM_INT32: return (int)*((const deUint32*)value);
320 case TextureFormat::SIGNED_INT8: return (int)*((const deInt8*)value);
321 case TextureFormat::SIGNED_INT16: return (int)*((const deInt16*)value);
322 case TextureFormat::SIGNED_INT32: return (int)*((const deInt32*)value);
323 case TextureFormat::UNSIGNED_INT8: return (int)*((const deUint8*)value);
324 case TextureFormat::UNSIGNED_INT16: return (int)*((const deUint16*)value);
325 case TextureFormat::UNSIGNED_INT24: return (int)readUint24(value);
326 case TextureFormat::UNSIGNED_INT32: return (int)*((const deUint32*)value);
327 case TextureFormat::HALF_FLOAT: return (int)deFloat16To32(*(const deFloat16*)value);
328 case TextureFormat::FLOAT: return (int)*((const float*)value);
329 case TextureFormat::FLOAT64: return (int)*((const double*)value);
330 case TextureFormat::UNORM_SHORT_10: return (int)((*(((const deUint16*)value))) >> 6u);
331 case TextureFormat::UNORM_SHORT_12: return (int)((*(((const deUint16*)value))) >> 4u);
338 void floatToChannel (deUint8* dst, float src, TextureFormat::ChannelType type)
340 // make sure this table is updated if format table is updated
341 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
345 case TextureFormat::SNORM_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src * 127.0f); break;
346 case TextureFormat::SNORM_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src * 32767.0f); break;
347 case TextureFormat::SNORM_INT32: *((deInt32*)dst) = convertSatRte<deInt32> (src * 2147483647.0f); break;
348 case TextureFormat::UNORM_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src * 255.0f); break;
349 case TextureFormat::UNORM_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src * 65535.0f); break;
350 case TextureFormat::UNORM_INT24: writeUint24(dst, convertSatRteUint24 (src * 16777215.0f)); break;
351 case TextureFormat::UNORM_INT32: *((deUint32*)dst) = convertSatRte<deUint32> (src * 4294967295.0f); break;
352 case TextureFormat::SIGNED_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src); break;
353 case TextureFormat::SIGNED_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src); break;
354 case TextureFormat::SIGNED_INT32: *((deInt32*)dst) = convertSatRte<deInt32> (src); break;
355 case TextureFormat::UNSIGNED_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src); break;
356 case TextureFormat::UNSIGNED_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src); break;
357 case TextureFormat::UNSIGNED_INT24: writeUint24(dst, convertSatRteUint24 (src)); break;
358 case TextureFormat::UNSIGNED_INT32: *((deUint32*)dst) = convertSatRte<deUint32> (src); break;
359 case TextureFormat::HALF_FLOAT: *((deFloat16*)dst) = deFloat32To16 (src); break;
360 case TextureFormat::FLOAT: *((float*)dst) = src; break;
361 case TextureFormat::FLOAT64: *((double*)dst) = (double)src; break;
362 case TextureFormat::UNORM_SHORT_10: *((deUint16*)dst) = (deUint16)(convertSatRteUint10(src * 1023.0f) << 6u); break;
363 case TextureFormat::UNORM_SHORT_12: *((deUint16*)dst) = (deUint16)(convertSatRteUint12(src * 4095.0f) << 4u); break;
369 template <typename T, typename S>
370 static inline T convertSat (S src)
372 S min = (S)std::numeric_limits<T>::min();
373 S max = (S)std::numeric_limits<T>::max();
383 template <typename S>
384 static inline deUint32 convertSatUint24 (S src)
387 S max = (S)0xFFFFFFu;
390 return (deUint32)min;
392 return (deUint32)max;
394 return (deUint32)src;
397 template <typename S>
398 static inline deUint16 convertSatUint10 (S src)
404 return (deUint16)min;
406 return (deUint16)max;
408 return (deUint16)src;
411 template <typename S>
412 static inline deUint16 convertSatUint12 (S src)
418 return (deUint16)min;
420 return (deUint16)max;
422 return (deUint16)src;
425 void intToChannel (deUint8* dst, int src, TextureFormat::ChannelType type)
427 // make sure this table is updated if format table is updated
428 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
432 case TextureFormat::SNORM_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
433 case TextureFormat::SNORM_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
434 case TextureFormat::UNORM_INT8: *((deUint8*)dst) = convertSat<deUint8> (src); break;
435 case TextureFormat::UNORM_INT16: *((deUint16*)dst) = convertSat<deUint16> (src); break;
436 case TextureFormat::UNORM_INT24: writeUint24(dst, convertSatUint24 (src)); break;
437 case TextureFormat::SIGNED_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
438 case TextureFormat::SIGNED_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
439 case TextureFormat::SIGNED_INT32: *((deInt32*)dst) = convertSat<deInt32> (src); break;
440 case TextureFormat::UNSIGNED_INT8: *((deUint8*)dst) = convertSat<deUint8> ((deUint32)src); break;
441 case TextureFormat::UNSIGNED_INT16: *((deUint16*)dst) = convertSat<deUint16> ((deUint32)src); break;
442 case TextureFormat::UNSIGNED_INT24: writeUint24(dst, convertSatUint24 ((deUint32)src)); break;
443 case TextureFormat::UNSIGNED_INT32: *((deUint32*)dst) = convertSat<deUint32> ((deUint32)src); break;
444 case TextureFormat::HALF_FLOAT: *((deFloat16*)dst) = deFloat32To16((float)src); break;
445 case TextureFormat::FLOAT: *((float*)dst) = (float)src; break;
446 case TextureFormat::FLOAT64: *((double*)dst) = (double)src; break;
447 case TextureFormat::UNORM_SHORT_10: *((deUint16*)dst) = (deUint16)(convertSatUint10(src) << 6u); break;
448 case TextureFormat::UNORM_SHORT_12: *((deUint16*)dst) = (deUint16)(convertSatUint12(src) << 4u); break;
454 inline float channelToUnormFloat (deUint32 src, int bits)
456 const deUint32 maxVal = (1u << bits) - 1;
458 // \note Will lose precision if bits > 23
459 return (float)src / (float)maxVal;
462 //! Extend < 32b signed integer to 32b
463 inline deInt32 signExtend (deUint32 src, int bits)
465 const deUint32 signBit = 1u << (bits-1);
467 src |= ~((src & signBit) - 1);
472 inline float channelToSnormFloat (deUint32 src, int bits)
474 const deUint32 range = (1u << (bits-1)) - 1;
476 // \note Will lose precision if bits > 24
477 return de::max(-1.0f, (float)signExtend(src, bits) / (float)range);
480 inline deUint32 unormFloatToChannel (float src, int bits)
482 const deUint32 maxVal = (1u << bits) - 1;
483 const deUint32 intVal = convertSatRte<deUint32>(src * (float)maxVal);
485 return de::min(intVal, maxVal);
488 inline deUint32 snormFloatToChannel (float src, int bits)
490 const deInt32 range = (deInt32)((1u << (bits-1)) - 1u);
491 const deUint32 mask = (1u << bits) - 1;
492 const deInt32 intVal = convertSatRte<deInt32>(src * (float)range);
494 return (deUint32)de::clamp(intVal, -range, range) & mask;
497 inline deUint32 uintToChannel (deUint32 src, int bits)
499 const deUint32 maxVal = (1u << bits) - 1;
500 return de::min(src, maxVal);
503 inline deUint32 intToChannel (deInt32 src, int bits)
505 const deInt32 minVal = -(deInt32)(1u << (bits-1));
506 const deInt32 maxVal = (deInt32)((1u << (bits-1)) - 1u);
507 const deUint32 mask = (1u << bits) - 1;
509 return (deUint32)de::clamp(src, minVal, maxVal) & mask;
512 tcu::Vec4 unpackRGB999E5 (deUint32 color)
515 const int eBias = 15;
517 deUint32 exp = color >> 27;
518 deUint32 bs = (color >> 18) & ((1<<9)-1);
519 deUint32 gs = (color >> 9) & ((1<<9)-1);
520 deUint32 rs = color & ((1<<9)-1);
522 float e = deFloatPow(2.0f, (float)((int)exp - eBias - mBits));
523 float r = (float)rs * e;
524 float g = (float)gs * e;
525 float b = (float)bs * e;
527 return tcu::Vec4(r, g, b, 1.0f);
530 bool isColorOrder (TextureFormat::ChannelOrder order)
532 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
536 case TextureFormat::R:
537 case TextureFormat::A:
538 case TextureFormat::I:
539 case TextureFormat::L:
540 case TextureFormat::LA:
541 case TextureFormat::RG:
542 case TextureFormat::RA:
543 case TextureFormat::RGB:
544 case TextureFormat::RGBA:
545 case TextureFormat::ARGB:
546 case TextureFormat::BGR:
547 case TextureFormat::BGRA:
548 case TextureFormat::sR:
549 case TextureFormat::sRG:
550 case TextureFormat::sRGB:
551 case TextureFormat::sRGBA:
552 case TextureFormat::sBGR:
553 case TextureFormat::sBGRA:
563 bool isValid (TextureFormat format)
565 const bool isColor = isColorOrder(format.order);
569 case TextureFormat::SNORM_INT8:
570 case TextureFormat::SNORM_INT16:
571 case TextureFormat::SNORM_INT32:
574 case TextureFormat::UNORM_INT8:
575 case TextureFormat::UNORM_INT16:
576 case TextureFormat::UNORM_INT24:
577 case TextureFormat::UNORM_INT32:
578 return isColor || format.order == TextureFormat::D;
580 case TextureFormat::UNORM_BYTE_44:
581 case TextureFormat::UNSIGNED_BYTE_44:
582 return format.order == TextureFormat::RG;
584 case TextureFormat::UNORM_SHORT_565:
585 case TextureFormat::UNORM_SHORT_555:
586 case TextureFormat::UNSIGNED_SHORT_565:
587 return format.order == TextureFormat::RGB || format.order == TextureFormat::BGR;
589 case TextureFormat::UNORM_SHORT_4444:
590 case TextureFormat::UNORM_SHORT_5551:
591 case TextureFormat::UNSIGNED_SHORT_4444:
592 case TextureFormat::UNSIGNED_SHORT_5551:
593 return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
595 case TextureFormat::UNORM_SHORT_1555:
596 return format.order == TextureFormat::ARGB;
598 case TextureFormat::UNORM_INT_101010:
599 return format.order == TextureFormat::RGB;
601 case TextureFormat::SNORM_INT_1010102_REV:
602 case TextureFormat::UNORM_INT_1010102_REV:
603 case TextureFormat::SIGNED_INT_1010102_REV:
604 case TextureFormat::UNSIGNED_INT_1010102_REV:
605 return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
607 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
608 case TextureFormat::UNSIGNED_INT_999_E5_REV:
609 return format.order == TextureFormat::RGB;
611 case TextureFormat::UNSIGNED_INT_16_8_8:
612 return format.order == TextureFormat::DS;
614 case TextureFormat::UNSIGNED_INT_24_8:
615 case TextureFormat::UNSIGNED_INT_24_8_REV:
616 return format.order == TextureFormat::D || format.order == TextureFormat::DS;
618 case TextureFormat::SIGNED_INT8:
619 case TextureFormat::SIGNED_INT16:
620 case TextureFormat::SIGNED_INT32:
623 case TextureFormat::UNSIGNED_INT8:
624 case TextureFormat::UNSIGNED_INT16:
625 case TextureFormat::UNSIGNED_INT24:
626 case TextureFormat::UNSIGNED_INT32:
627 return isColor || format.order == TextureFormat::S;
629 case TextureFormat::HALF_FLOAT:
630 case TextureFormat::FLOAT:
631 case TextureFormat::FLOAT64:
632 return isColor || format.order == TextureFormat::D;
634 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
635 return format.order == TextureFormat::DS;
637 case TextureFormat::UNORM_SHORT_10:
638 case TextureFormat::UNORM_SHORT_12:
642 DE_FATAL("Unknown format");
646 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
649 int getNumUsedChannels (TextureFormat::ChannelOrder order)
651 // make sure this table is updated if type table is updated
652 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
656 case TextureFormat::R: return 1;
657 case TextureFormat::A: return 1;
658 case TextureFormat::I: return 1;
659 case TextureFormat::L: return 1;
660 case TextureFormat::LA: return 2;
661 case TextureFormat::RG: return 2;
662 case TextureFormat::RA: return 2;
663 case TextureFormat::RGB: return 3;
664 case TextureFormat::RGBA: return 4;
665 case TextureFormat::ARGB: return 4;
666 case TextureFormat::BGR: return 3;
667 case TextureFormat::BGRA: return 4;
668 case TextureFormat::sR: return 1;
669 case TextureFormat::sRG: return 2;
670 case TextureFormat::sRGB: return 3;
671 case TextureFormat::sRGBA: return 4;
672 case TextureFormat::sBGR: return 3;
673 case TextureFormat::sBGRA: return 4;
674 case TextureFormat::D: return 1;
675 case TextureFormat::S: return 1;
676 case TextureFormat::DS: return 2;
683 int getChannelSize (TextureFormat::ChannelType type)
685 // make sure this table is updated if format table is updated
686 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
690 case TextureFormat::SNORM_INT8: return 1;
691 case TextureFormat::SNORM_INT16: return 2;
692 case TextureFormat::SNORM_INT32: return 4;
693 case TextureFormat::UNORM_INT8: return 1;
694 case TextureFormat::UNORM_INT16: return 2;
695 case TextureFormat::UNORM_INT24: return 3;
696 case TextureFormat::UNORM_INT32: return 4;
697 case TextureFormat::SIGNED_INT8: return 1;
698 case TextureFormat::SIGNED_INT16: return 2;
699 case TextureFormat::SIGNED_INT32: return 4;
700 case TextureFormat::UNSIGNED_INT8: return 1;
701 case TextureFormat::UNSIGNED_INT16: return 2;
702 case TextureFormat::UNSIGNED_INT24: return 3;
703 case TextureFormat::UNSIGNED_INT32: return 4;
704 case TextureFormat::HALF_FLOAT: return 2;
705 case TextureFormat::FLOAT: return 4;
706 case TextureFormat::FLOAT64: return 8;
707 case TextureFormat::UNORM_SHORT_10: return 2;
708 case TextureFormat::UNORM_SHORT_12: return 2;
715 /** Get pixel size in bytes. */
716 int getPixelSize (TextureFormat format)
718 const TextureFormat::ChannelOrder order = format.order;
719 const TextureFormat::ChannelType type = format.type;
721 DE_ASSERT(isValid(format));
723 // make sure this table is updated if format table is updated
724 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
728 case TextureFormat::UNORM_BYTE_44:
729 case TextureFormat::UNSIGNED_BYTE_44:
732 case TextureFormat::UNORM_SHORT_565:
733 case TextureFormat::UNORM_SHORT_555:
734 case TextureFormat::UNORM_SHORT_4444:
735 case TextureFormat::UNORM_SHORT_5551:
736 case TextureFormat::UNORM_SHORT_1555:
737 case TextureFormat::UNSIGNED_SHORT_565:
738 case TextureFormat::UNSIGNED_SHORT_4444:
739 case TextureFormat::UNSIGNED_SHORT_5551:
742 case TextureFormat::UNORM_INT_101010:
743 case TextureFormat::UNSIGNED_INT_999_E5_REV:
744 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
745 case TextureFormat::SNORM_INT_1010102_REV:
746 case TextureFormat::UNORM_INT_1010102_REV:
747 case TextureFormat::SIGNED_INT_1010102_REV:
748 case TextureFormat::UNSIGNED_INT_1010102_REV:
749 case TextureFormat::UNSIGNED_INT_24_8:
750 case TextureFormat::UNSIGNED_INT_24_8_REV:
751 case TextureFormat::UNSIGNED_INT_16_8_8:
754 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
758 return getNumUsedChannels(order) * getChannelSize(type);
762 int TextureFormat::getPixelSize (void) const
764 return ::tcu::getPixelSize(*this);
767 const TextureSwizzle& getChannelReadSwizzle (TextureFormat::ChannelOrder order)
769 // make sure to update these tables when channel orders are updated
770 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
772 static const TextureSwizzle INV = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
773 static const TextureSwizzle R = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
774 static const TextureSwizzle A = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_0 }};
775 static const TextureSwizzle I = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0 }};
776 static const TextureSwizzle L = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE }};
777 static const TextureSwizzle LA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1 }};
778 static const TextureSwizzle RG = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
779 static const TextureSwizzle RA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_1 }};
780 static const TextureSwizzle RGB = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_ONE }};
781 static const TextureSwizzle RGBA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3 }};
782 static const TextureSwizzle BGR = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE }};
783 static const TextureSwizzle BGRA = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3 }};
784 static const TextureSwizzle ARGB = {{ TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_0 }};
785 static const TextureSwizzle D = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
786 static const TextureSwizzle S = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
790 case TextureFormat::R: return R;
791 case TextureFormat::A: return A;
792 case TextureFormat::I: return I;
793 case TextureFormat::L: return L;
794 case TextureFormat::LA: return LA;
795 case TextureFormat::RG: return RG;
796 case TextureFormat::RA: return RA;
797 case TextureFormat::RGB: return RGB;
798 case TextureFormat::RGBA: return RGBA;
799 case TextureFormat::ARGB: return ARGB;
800 case TextureFormat::BGR: return BGR;
801 case TextureFormat::BGRA: return BGRA;
802 case TextureFormat::sR: return R;
803 case TextureFormat::sRG: return RG;
804 case TextureFormat::sRGB: return RGB;
805 case TextureFormat::sRGBA: return RGBA;
806 case TextureFormat::sBGR: return BGR;
807 case TextureFormat::sBGRA: return BGRA;
808 case TextureFormat::D: return D;
809 case TextureFormat::S: return S;
811 case TextureFormat::DS:
812 DE_ASSERT(false); // combined formats cannot be read from
821 const TextureSwizzle& getChannelWriteSwizzle (TextureFormat::ChannelOrder order)
823 // make sure to update these tables when channel orders are updated
824 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
826 static const TextureSwizzle INV = {{ TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
827 static const TextureSwizzle R = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
828 static const TextureSwizzle A = {{ TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
829 static const TextureSwizzle I = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
830 static const TextureSwizzle L = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
831 static const TextureSwizzle LA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
832 static const TextureSwizzle RG = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
833 static const TextureSwizzle RA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
834 static const TextureSwizzle RGB = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_LAST }};
835 static const TextureSwizzle RGBA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3 }};
836 static const TextureSwizzle BGR = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST }};
837 static const TextureSwizzle BGRA = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3 }};
838 static const TextureSwizzle ARGB = {{ TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2 }};
839 static const TextureSwizzle D = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
840 static const TextureSwizzle S = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
844 case TextureFormat::R: return R;
845 case TextureFormat::A: return A;
846 case TextureFormat::I: return I;
847 case TextureFormat::L: return L;
848 case TextureFormat::LA: return LA;
849 case TextureFormat::RG: return RG;
850 case TextureFormat::RA: return RA;
851 case TextureFormat::RGB: return RGB;
852 case TextureFormat::RGBA: return RGBA;
853 case TextureFormat::ARGB: return ARGB;
854 case TextureFormat::BGR: return BGR;
855 case TextureFormat::BGRA: return BGRA;
856 case TextureFormat::sR: return R;
857 case TextureFormat::sRG: return RG;
858 case TextureFormat::sRGB: return RGB;
859 case TextureFormat::sRGBA: return RGBA;
860 case TextureFormat::sBGR: return BGR;
861 case TextureFormat::sBGRA: return BGRA;
862 case TextureFormat::D: return D;
863 case TextureFormat::S: return S;
865 case TextureFormat::DS:
866 DE_ASSERT(false); // combined formats cannot be written to
875 IVec3 calculatePackedPitch (const TextureFormat& format, const IVec3& size)
877 const int pixelSize = format.getPixelSize();
878 const int rowPitch = pixelSize * size.x();
879 const int slicePitch = rowPitch * size.y();
881 return IVec3(pixelSize, rowPitch, slicePitch);
884 ConstPixelBufferAccess::ConstPixelBufferAccess (void)
891 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, const void* data)
893 , m_size (width, height, depth)
894 , m_pitch (calculatePackedPitch(m_format, m_size))
895 , m_data ((void*)data)
897 DE_ASSERT(isValid(format));
900 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const void* data)
903 , m_pitch (calculatePackedPitch(m_format, m_size))
904 , m_data ((void*)data)
906 DE_ASSERT(isValid(format));
909 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, const void* data)
911 , m_size (width, height, depth)
912 , m_pitch (format.getPixelSize(), rowPitch, slicePitch)
913 , m_data ((void*)data)
915 DE_ASSERT(isValid(format));
918 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, const void* data)
922 , m_data ((void*)data)
924 DE_ASSERT(isValid(format));
925 DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
928 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureLevel& level)
929 : m_format (level.getFormat())
930 , m_size (level.getSize())
931 , m_pitch (calculatePackedPitch(m_format, m_size))
932 , m_data ((void*)level.getPtr())
936 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data)
937 : ConstPixelBufferAccess(format, width, height, depth, data)
941 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, void* data)
942 : ConstPixelBufferAccess(format, size, data)
946 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, void* data)
947 : ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, data)
951 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, void* data)
952 : ConstPixelBufferAccess(format, size, pitch, data)
956 PixelBufferAccess::PixelBufferAccess (TextureLevel& level)
957 : ConstPixelBufferAccess(level)
961 //! Swizzle RGB(A) <-> BGR(A)
963 Vector<T, 4> swizzleRB (const Vector<T, 4>& v, TextureFormat::ChannelOrder src, TextureFormat::ChannelOrder dst)
969 DE_ASSERT((src == TextureFormat::RGB && dst == TextureFormat::BGR) ||
970 (src == TextureFormat::BGR && dst == TextureFormat::RGB) ||
971 (src == TextureFormat::RGBA && dst == TextureFormat::BGRA) ||
972 (src == TextureFormat::BGRA && dst == TextureFormat::RGBA));
973 return v.swizzle(2,1,0,3);
977 Vec4 ConstPixelBufferAccess::getPixel (int x, int y, int z) const
979 DE_ASSERT(de::inBounds(x, 0, m_size.x()));
980 DE_ASSERT(de::inBounds(y, 0, m_size.y()));
981 DE_ASSERT(de::inBounds(z, 0, m_size.z()));
982 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
983 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
985 const deUint8* pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
988 if (m_format.type == TextureFormat::UNORM_INT8)
990 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
991 return readRGBA8888Float(pixelPtr);
992 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
993 return readRGB888Float(pixelPtr);
996 #define UI8(OFFS, COUNT) ((*((const deUint8*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
997 #define UI16(OFFS, COUNT) ((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
998 #define UI32(OFFS, COUNT) ((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
999 #define SI32(OFFS, COUNT) signExtend(UI32(OFFS, COUNT), (COUNT))
1000 #define UN8(OFFS, COUNT) channelToUnormFloat(UI8 (OFFS, COUNT), (COUNT))
1001 #define UN16(OFFS, COUNT) channelToUnormFloat(UI16(OFFS, COUNT), (COUNT))
1002 #define UN32(OFFS, COUNT) channelToUnormFloat(UI32(OFFS, COUNT), (COUNT))
1003 #define SN32(OFFS, COUNT) channelToSnormFloat(UI32(OFFS, COUNT), (COUNT))
1006 switch (m_format.type)
1008 case TextureFormat::UNORM_BYTE_44: return Vec4(UN8 (4, 4), UN8 ( 0, 4), 0.0f, 1.0f);
1009 case TextureFormat::UNSIGNED_BYTE_44: return UVec4(UI8 (4, 4), UI8 ( 0, 4), 0u, 1u).cast<float>();
1010 case TextureFormat::UNORM_SHORT_565: return swizzleRB( Vec4(UN16(11, 5), UN16( 5, 6), UN16( 0, 5), 1.0f), m_format.order, TextureFormat::RGB);
1011 case TextureFormat::UNSIGNED_SHORT_565: return swizzleRB(UVec4(UI16(11, 5), UI16( 5, 6), UI16( 0, 5), 1u), m_format.order, TextureFormat::RGB).cast<float>();
1012 case TextureFormat::UNORM_SHORT_555: return swizzleRB( Vec4(UN16(10, 5), UN16( 5, 5), UN16( 0, 5), 1.0f), m_format.order, TextureFormat::RGB);
1013 case TextureFormat::UNORM_SHORT_4444: return swizzleRB( Vec4(UN16(12, 4), UN16( 8, 4), UN16( 4, 4), UN16( 0, 4)), m_format.order, TextureFormat::RGBA);
1014 case TextureFormat::UNSIGNED_SHORT_4444: return swizzleRB(UVec4(UI16(12, 4), UI16( 8, 4), UI16( 4, 4), UI16( 0, 4)), m_format.order, TextureFormat::RGBA).cast<float>();
1015 case TextureFormat::UNORM_SHORT_5551: return swizzleRB( Vec4(UN16(11, 5), UN16( 6, 5), UN16( 1, 5), UN16( 0, 1)), m_format.order, TextureFormat::RGBA);
1016 case TextureFormat::UNSIGNED_SHORT_5551: return swizzleRB(UVec4(UI16(11, 5), UI16( 6, 5), UI16( 1, 5), UI16( 0, 1)), m_format.order, TextureFormat::RGBA).cast<float>();
1017 case TextureFormat::UNORM_INT_101010: return Vec4(UN32(22, 10), UN32(12, 10), UN32( 2, 10), 1.0f);
1018 case TextureFormat::UNORM_INT_1010102_REV: return swizzleRB( Vec4(UN32( 0, 10), UN32(10, 10), UN32(20, 10), UN32(30, 2)), m_format.order, TextureFormat::RGBA);
1019 case TextureFormat::SNORM_INT_1010102_REV: return swizzleRB( Vec4(SN32( 0, 10), SN32(10, 10), SN32(20, 10), SN32(30, 2)), m_format.order, TextureFormat::RGBA);
1020 case TextureFormat::UNSIGNED_INT_1010102_REV: return swizzleRB( UVec4(UI32(0, 10), UI32(10, 10), UI32(20, 10), UI32(30, 2)), m_format.order, TextureFormat::RGBA).cast<float>();
1021 case TextureFormat::SIGNED_INT_1010102_REV: return swizzleRB( UVec4(SI32(0, 10), SI32(10, 10), SI32(20, 10), SI32(30, 2)), m_format.order, TextureFormat::RGBA).cast<float>();
1022 case TextureFormat::UNSIGNED_INT_999_E5_REV: return unpackRGB999E5(*((const deUint32*)pixelPtr));
1024 case TextureFormat::UNORM_SHORT_1555:
1025 DE_ASSERT(m_format.order == TextureFormat::ARGB);
1026 return Vec4(UN16(15, 1), UN16(10, 5), UN16(5, 5), UN16(0, 5)).swizzle(1,2,3,0); // ARGB -> RGBA
1028 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
1029 return Vec4(Float11(UI32(0, 11)).asFloat(), Float11(UI32(11, 11)).asFloat(), Float10(UI32(22, 10)).asFloat(), 1.0f);
1046 const TextureSwizzle::Channel* channelMap = getChannelReadSwizzle(m_format.order).components;
1047 int channelSize = getChannelSize(m_format.type);
1049 for (int c = 0; c < 4; c++)
1051 switch (channelMap[c])
1053 case TextureSwizzle::CHANNEL_0:
1054 case TextureSwizzle::CHANNEL_1:
1055 case TextureSwizzle::CHANNEL_2:
1056 case TextureSwizzle::CHANNEL_3:
1057 result[c] = channelToFloat(pixelPtr + channelSize*((int)channelMap[c]), m_format.type);
1060 case TextureSwizzle::CHANNEL_ZERO:
1064 case TextureSwizzle::CHANNEL_ONE:
1076 IVec4 ConstPixelBufferAccess::getPixelInt (int x, int y, int z) const
1078 DE_ASSERT(de::inBounds(x, 0, m_size.x()));
1079 DE_ASSERT(de::inBounds(y, 0, m_size.y()));
1080 DE_ASSERT(de::inBounds(z, 0, m_size.z()));
1081 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1082 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1084 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1087 // Optimized fomats.
1088 if (m_format.type == TextureFormat::UNORM_INT8)
1090 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1091 return readRGBA8888Int(pixelPtr);
1092 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1093 return readRGB888Int(pixelPtr);
1096 #define U8(OFFS, COUNT) ((*((const deUint8* )pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1097 #define U16(OFFS, COUNT) ((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1098 #define U32(OFFS, COUNT) ((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1099 #define S32(OFFS, COUNT) signExtend(U32(OFFS, COUNT), (COUNT))
1101 switch (m_format.type)
1103 case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
1104 case TextureFormat::UNORM_BYTE_44: return UVec4(U8 ( 4, 4), U8 ( 0, 4), 0u, 1u).cast<int>();
1105 case TextureFormat::UNSIGNED_SHORT_565: // Fall-through
1106 case TextureFormat::UNORM_SHORT_565: return swizzleRB(UVec4(U16(11, 5), U16( 5, 6), U16( 0, 5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
1107 case TextureFormat::UNORM_SHORT_555: return swizzleRB(UVec4(U16(10, 5), U16( 5, 5), U16( 0, 5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
1108 case TextureFormat::UNSIGNED_SHORT_4444: // Fall-through
1109 case TextureFormat::UNORM_SHORT_4444: return swizzleRB(UVec4(U16(12, 4), U16( 8, 4), U16( 4, 4), U16( 0, 4)).cast<int>(), m_format.order, TextureFormat::RGBA);
1110 case TextureFormat::UNSIGNED_SHORT_5551: // Fall-through
1111 case TextureFormat::UNORM_SHORT_5551: return swizzleRB(UVec4(U16(11, 5), U16( 6, 5), U16( 1, 5), U16( 0, 1)).cast<int>(), m_format.order, TextureFormat::RGBA);
1112 case TextureFormat::UNORM_INT_101010: return UVec4(U32(22, 10), U32(12, 10), U32( 2, 10), 1).cast<int>();
1113 case TextureFormat::UNORM_INT_1010102_REV: // Fall-through
1114 case TextureFormat::UNSIGNED_INT_1010102_REV: return swizzleRB(UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)), m_format.order, TextureFormat::RGBA).cast<int>();
1115 case TextureFormat::SNORM_INT_1010102_REV: // Fall-through
1116 case TextureFormat::SIGNED_INT_1010102_REV: return swizzleRB(IVec4(S32( 0, 10), S32(10, 10), S32(20, 10), S32(30, 2)), m_format.order, TextureFormat::RGBA);
1118 case TextureFormat::UNORM_SHORT_1555:
1119 DE_ASSERT(m_format.order == TextureFormat::ARGB);
1120 return UVec4(U16(15, 1), U16(10, 5), U16(5, 5), U16(0, 5)).cast<int>().swizzle(1,2,3,0); // ARGB -> RGBA
1123 break; // To generic path.
1132 const TextureSwizzle::Channel* channelMap = getChannelReadSwizzle(m_format.order).components;
1133 int channelSize = getChannelSize(m_format.type);
1135 for (int c = 0; c < 4; c++)
1137 switch (channelMap[c])
1139 case TextureSwizzle::CHANNEL_0:
1140 case TextureSwizzle::CHANNEL_1:
1141 case TextureSwizzle::CHANNEL_2:
1142 case TextureSwizzle::CHANNEL_3:
1143 result[c] = channelToInt(pixelPtr + channelSize*((int)channelMap[c]), m_format.type);
1146 case TextureSwizzle::CHANNEL_ZERO:
1150 case TextureSwizzle::CHANNEL_ONE:
1163 Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1165 return getPixel(x, y, z);
1169 IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1171 return getPixelInt(x, y, z);
1175 UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1177 return getPixelUint(x, y, z);
1180 float ConstPixelBufferAccess::getPixDepth (int x, int y, int z) const
1182 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1183 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1184 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1186 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1188 switch (m_format.type)
1190 case TextureFormat::UNSIGNED_INT_16_8_8:
1191 DE_ASSERT(m_format.order == TextureFormat::DS);
1192 return (float)readUint32High16(pixelPtr) / 65535.0f;
1194 case TextureFormat::UNSIGNED_INT_24_8:
1195 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1196 return (float)readUint32High24(pixelPtr) / 16777215.0f;
1198 case TextureFormat::UNSIGNED_INT_24_8_REV:
1199 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1200 return (float)readUint32Low24(pixelPtr) / 16777215.0f;
1202 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1203 DE_ASSERT(m_format.order == TextureFormat::DS);
1204 return *((const float*)pixelPtr);
1207 DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1208 return channelToFloat(pixelPtr, m_format.type);
1212 int ConstPixelBufferAccess::getPixStencil (int x, int y, int z) const
1214 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1215 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1216 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1218 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1220 switch (m_format.type)
1222 case TextureFormat::UNSIGNED_INT_24_8_REV:
1223 DE_ASSERT(m_format.order == TextureFormat::DS);
1224 return (int)readUint32High8(pixelPtr);
1226 case TextureFormat::UNSIGNED_INT_16_8_8:
1227 case TextureFormat::UNSIGNED_INT_24_8:
1228 DE_ASSERT(m_format.order == TextureFormat::DS);
1229 return (int)readUint32Low8(pixelPtr);
1231 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1232 DE_ASSERT(m_format.order == TextureFormat::DS);
1233 return (int)readUint32Low8(pixelPtr + 4);
1237 DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1238 return channelToInt(pixelPtr, m_format.type);
1243 void PixelBufferAccess::setPixel (const Vec4& color, int x, int y, int z) const
1245 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1246 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1247 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1248 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1249 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1251 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1253 // Optimized fomats.
1254 if (m_format.type == TextureFormat::UNORM_INT8)
1256 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1258 writeRGBA8888Float(pixelPtr, color);
1261 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1263 writeRGB888Float(pixelPtr, color);
1268 #define PN(VAL, OFFS, BITS) (unormFloatToChannel((VAL), (BITS)) << (OFFS))
1269 #define PS(VAL, OFFS, BITS) (snormFloatToChannel((VAL), (BITS)) << (OFFS))
1270 #define PU(VAL, OFFS, BITS) (uintToChannel((VAL), (BITS)) << (OFFS))
1271 #define PI(VAL, OFFS, BITS) (intToChannel((VAL), (BITS)) << (OFFS))
1273 switch (m_format.type)
1275 case TextureFormat::UNORM_BYTE_44: *((deUint8 *)pixelPtr) = (deUint8)(PN(color[0], 4, 4) | PN(color[1], 0, 4)); break;
1276 case TextureFormat::UNSIGNED_BYTE_44: *((deUint8 *)pixelPtr) = (deUint8)(PU((deUint32)color[0], 4, 4) | PU((deUint32)color[1], 0, 4)); break;
1277 case TextureFormat::UNORM_INT_101010: *((deUint32*)pixelPtr) = PN(color[0], 22, 10) | PN(color[1], 12, 10) | PN(color[2], 2, 10); break;
1279 case TextureFormat::UNORM_SHORT_565:
1281 const Vec4 swizzled = swizzleRB(color, TextureFormat::RGB, m_format.order);
1282 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 5, 6) | PN(swizzled[2], 0, 5));
1286 case TextureFormat::UNSIGNED_SHORT_565:
1288 const UVec4 swizzled = swizzleRB(color.cast<deUint32>(), TextureFormat::RGB, m_format.order);
1289 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
1293 case TextureFormat::UNORM_SHORT_555:
1295 const Vec4 swizzled = swizzleRB(color, TextureFormat::RGB, m_format.order);
1296 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 10, 5) | PN(swizzled[1], 5, 5) | PN(swizzled[2], 0, 5));
1300 case TextureFormat::UNORM_SHORT_4444:
1302 const Vec4 swizzled = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1303 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 12, 4) | PN(swizzled[1], 8, 4) | PN(swizzled[2], 4, 4) | PN(swizzled[3], 0, 4));
1307 case TextureFormat::UNSIGNED_SHORT_4444:
1309 const UVec4 swizzled = swizzleRB(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1310 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
1314 case TextureFormat::UNORM_SHORT_5551:
1316 const Vec4 swizzled = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1317 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 6, 5) | PN(swizzled[2], 1, 5) | PN(swizzled[3], 0, 1));
1321 case TextureFormat::UNORM_SHORT_1555:
1323 const Vec4 swizzled = color.swizzle(3,0,1,2); // RGBA -> ARGB
1324 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 15, 1) | PN(swizzled[1], 10, 5) | PN(swizzled[2], 5, 5) | PN(swizzled[3], 0, 5));
1328 case TextureFormat::UNSIGNED_SHORT_5551:
1330 const UVec4 swizzled = swizzleRB(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1331 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
1335 case TextureFormat::UNORM_INT_1010102_REV:
1337 const Vec4 u = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1338 *((deUint32*)pixelPtr) = PN(u[0], 0, 10) | PN(u[1], 10, 10) | PN(u[2], 20, 10) | PN(u[3], 30, 2);
1342 case TextureFormat::SNORM_INT_1010102_REV:
1344 const Vec4 u = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1345 *((deUint32*)pixelPtr) = PS(u[0], 0, 10) | PS(u[1], 10, 10) | PS(u[2], 20, 10) | PS(u[3], 30, 2);
1349 case TextureFormat::UNSIGNED_INT_1010102_REV:
1351 const UVec4 u = swizzleRB(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1352 *((deUint32*)pixelPtr) = PU(u[0], 0, 10) | PU(u[1], 10, 10) | PU(u[2], 20, 10) | PU(u[3], 30, 2);
1356 case TextureFormat::SIGNED_INT_1010102_REV:
1358 const IVec4 u = swizzleRB(color.cast<deInt32>(), TextureFormat::RGBA, m_format.order);
1359 *((deUint32*)pixelPtr) = PI(u[0], 0, 10) | PI(u[1], 10, 10) | PI(u[2], 20, 10) | PI(u[3], 30, 2);
1363 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
1364 *((deUint32*)pixelPtr) = Float11(color[0]).bits() | (Float11(color[1]).bits() << 11) | (Float10(color[2]).bits() << 22);
1367 case TextureFormat::UNSIGNED_INT_999_E5_REV:
1368 *((deUint32*)pixelPtr) = packRGB999E5(color);
1374 int numChannels = getNumUsedChannels(m_format.order);
1375 const TextureSwizzle::Channel* map = getChannelWriteSwizzle(m_format.order).components;
1376 int channelSize = getChannelSize(m_format.type);
1378 for (int c = 0; c < numChannels; c++)
1380 DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1381 floatToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1393 void PixelBufferAccess::setPixel (const IVec4& color, int x, int y, int z) const
1395 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1396 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1397 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1398 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1399 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1401 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1403 // Optimized fomats.
1404 if (m_format.type == TextureFormat::UNORM_INT8)
1406 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1408 writeRGBA8888Int(pixelPtr, color);
1411 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1413 writeRGB888Int(pixelPtr, color);
1418 #define PU(VAL, OFFS, BITS) (uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1419 #define PI(VAL, OFFS, BITS) (intToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1421 switch (m_format.type)
1423 case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
1424 case TextureFormat::UNORM_BYTE_44: *((deUint8 *)pixelPtr) = (deUint8 )(PU(color[0], 4, 4) | PU(color[1], 0, 4)); break;
1425 case TextureFormat::UNORM_INT_101010: *((deUint32*)pixelPtr) = PU(color[0], 22, 10) | PU(color[1], 12, 10) | PU(color[2], 2, 10); break;
1427 case TextureFormat::UNORM_SHORT_565:
1428 case TextureFormat::UNSIGNED_SHORT_565:
1430 const IVec4 swizzled = swizzleRB(color, TextureFormat::RGB, m_format.order);
1431 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
1435 case TextureFormat::UNORM_SHORT_555:
1437 const IVec4 swizzled = swizzleRB(color, TextureFormat::RGB, m_format.order);
1438 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 10, 5) | PU(swizzled[1], 5, 5) | PU(swizzled[2], 0, 5));
1442 case TextureFormat::UNORM_SHORT_4444:
1443 case TextureFormat::UNSIGNED_SHORT_4444:
1445 const IVec4 swizzled = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1446 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
1450 case TextureFormat::UNORM_SHORT_5551:
1451 case TextureFormat::UNSIGNED_SHORT_5551:
1453 const IVec4 swizzled = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1454 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
1458 case TextureFormat::UNORM_SHORT_1555:
1460 const IVec4 swizzled = color.swizzle(3,0,1,2); // RGBA -> ARGB
1461 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 15, 1) | PU(swizzled[1], 10, 5) | PU(swizzled[2], 5, 5) | PU(swizzled[3], 0, 5));
1465 case TextureFormat::UNORM_INT_1010102_REV:
1466 case TextureFormat::UNSIGNED_INT_1010102_REV:
1468 const IVec4 swizzled = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1469 *((deUint32*)pixelPtr) = PU(swizzled[0], 0, 10) | PU(swizzled[1], 10, 10) | PU(swizzled[2], 20, 10) | PU(swizzled[3], 30, 2);
1473 case TextureFormat::SNORM_INT_1010102_REV:
1474 case TextureFormat::SIGNED_INT_1010102_REV:
1476 const IVec4 swizzled = swizzleRB(color, TextureFormat::RGBA, m_format.order);
1477 *((deUint32*)pixelPtr) = PI(swizzled[0], 0, 10) | PI(swizzled[1], 10, 10) | PI(swizzled[2], 20, 10) | PI(swizzled[3], 30, 2);
1484 int numChannels = getNumUsedChannels(m_format.order);
1485 const TextureSwizzle::Channel* map = getChannelWriteSwizzle(m_format.order).components;
1486 int channelSize = getChannelSize(m_format.type);
1488 for (int c = 0; c < numChannels; c++)
1490 DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1491 intToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1501 void PixelBufferAccess::setPixDepth (float depth, int x, int y, int z) const
1503 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1504 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1505 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1507 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1509 switch (m_format.type)
1511 case TextureFormat::UNSIGNED_INT_16_8_8:
1512 DE_ASSERT(m_format.order == TextureFormat::DS);
1513 writeUint32High16(pixelPtr, convertSatRte<deUint16>(depth * 65535.0f));
1516 case TextureFormat::UNSIGNED_INT_24_8:
1517 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1518 writeUint32High24(pixelPtr, convertSatRteUint24(depth * 16777215.0f));
1521 case TextureFormat::UNSIGNED_INT_24_8_REV:
1522 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1523 writeUint32Low24(pixelPtr, convertSatRteUint24(depth * 16777215.0f));
1526 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1527 DE_ASSERT(m_format.order == TextureFormat::DS);
1528 *((float*)pixelPtr) = depth;
1532 DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1533 floatToChannel(pixelPtr, depth, m_format.type);
1538 void PixelBufferAccess::setPixStencil (int stencil, int x, int y, int z) const
1540 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1541 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1542 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1544 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1546 switch (m_format.type)
1548 case TextureFormat::UNSIGNED_INT_16_8_8:
1549 case TextureFormat::UNSIGNED_INT_24_8:
1550 DE_ASSERT(m_format.order == TextureFormat::DS);
1551 writeUint32Low8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
1554 case TextureFormat::UNSIGNED_INT_24_8_REV:
1555 DE_ASSERT(m_format.order == TextureFormat::DS);
1556 writeUint32High8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
1559 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1560 DE_ASSERT(m_format.order == TextureFormat::DS);
1561 writeUint32Low8(pixelPtr + 4, convertSat<deUint8>((deUint32)stencil));
1565 DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1566 intToChannel(pixelPtr, stencil, m_format.type);
1571 static inline int imod (int a, int b)
1574 return m < 0 ? m + b : m;
1577 static inline int mirror (int a)
1579 return a >= 0 ? a : -(1 + a);
1582 // Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
1583 static inline float rint (float a)
1585 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
1587 float fracVal = deFloatFrac(a);
1589 if (fracVal != 0.5f)
1590 return deFloatRound(a); // Ordinary case.
1592 float floorVal = a - fracVal;
1593 bool roundUp = (deInt64)floorVal % 2 != 0;
1595 return floorVal + (roundUp ? 1.0f : 0.0f);
1598 static inline int wrap (Sampler::WrapMode mode, int c, int size)
1602 case tcu::Sampler::CLAMP_TO_BORDER:
1603 return deClamp32(c, -1, size);
1605 case tcu::Sampler::CLAMP_TO_EDGE:
1606 return deClamp32(c, 0, size-1);
1608 case tcu::Sampler::REPEAT_GL:
1609 return imod(c, size);
1611 case tcu::Sampler::REPEAT_CL:
1612 return imod(c, size);
1614 case tcu::Sampler::MIRRORED_ONCE:
1615 c = deClamp32(c, -size, size);
1618 case tcu::Sampler::MIRRORED_REPEAT_GL:
1619 return (size - 1) - mirror(imod(c, 2*size) - size);
1621 case tcu::Sampler::MIRRORED_REPEAT_CL:
1622 return deClamp32(c, 0, size-1); // \note Actual mirroring done already in unnormalization function.
1625 DE_ASSERT(DE_FALSE);
1630 // Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL wrap modes; otherwise ordinary unnormalization.
1631 static inline float unnormalize (Sampler::WrapMode mode, float c, int size)
1635 case tcu::Sampler::CLAMP_TO_EDGE:
1636 case tcu::Sampler::CLAMP_TO_BORDER:
1637 case tcu::Sampler::REPEAT_GL:
1638 case tcu::Sampler::MIRRORED_REPEAT_GL:
1639 case tcu::Sampler::MIRRORED_ONCE: // Fall-through (ordinary case).
1640 return (float)size*c;
1642 case tcu::Sampler::REPEAT_CL:
1643 return (float)size * (c - deFloatFloor(c));
1645 case tcu::Sampler::MIRRORED_REPEAT_CL:
1646 return (float)size * deFloatAbs(c - 2.0f * rint(0.5f * c));
1649 DE_ASSERT(DE_FALSE);
1654 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
1656 DE_ASSERT(format.order == TextureFormat::D);
1658 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
1659 if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
1661 else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1670 // Texel lookup with color conversion.
1671 static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, int k)
1673 const TextureFormat& format = access.getFormat();
1677 if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGB)
1678 return sRGB8ToLinear(access.getPixelUint(i, j, k));
1679 else if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGBA)
1680 return sRGBA8ToLinear(access.getPixelUint(i, j, k));
1682 return sRGBToLinear(access.getPixel(i, j, k));
1686 return access.getPixel(i, j, k);
1690 // Border texel lookup with color conversion.
1691 static inline Vec4 lookupBorder (const tcu::TextureFormat& format, const tcu::Sampler& sampler)
1693 // "lookup" for a combined format does not make sense, disallow
1694 DE_ASSERT(!isCombinedDepthStencilType(format.type));
1696 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
1697 const bool isFloat = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1698 const bool isFixed = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1699 channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1700 const bool isPureInteger = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
1701 const bool isPureUnsignedInteger = channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1703 if (isFloat || isFixed)
1704 return sampleTextureBorder<float>(format, sampler);
1705 else if (isPureInteger)
1706 return sampleTextureBorder<deInt32>(format, sampler).cast<float>();
1707 else if (isPureUnsignedInteger)
1708 return sampleTextureBorder<deUint32>(format, sampler).cast<float>();
1716 static inline float execCompare (const tcu::Vec4& color, Sampler::CompareMode compare, int chanNdx, float ref_, bool isFixedPoint)
1718 const bool clampValues = isFixedPoint; // if comparing against a floating point texture, ref (and value) is not clamped
1719 const float cmp = (clampValues) ? (de::clamp(color[chanNdx], 0.0f, 1.0f)) : (color[chanNdx]);
1720 const float ref = (clampValues) ? (de::clamp(ref_, 0.0f, 1.0f)) : (ref_);
1725 case Sampler::COMPAREMODE_LESS: res = ref < cmp; break;
1726 case Sampler::COMPAREMODE_LESS_OR_EQUAL: res = ref <= cmp; break;
1727 case Sampler::COMPAREMODE_GREATER: res = ref > cmp; break;
1728 case Sampler::COMPAREMODE_GREATER_OR_EQUAL: res = ref >= cmp; break;
1729 case Sampler::COMPAREMODE_EQUAL: res = ref == cmp; break;
1730 case Sampler::COMPAREMODE_NOT_EQUAL: res = ref != cmp; break;
1731 case Sampler::COMPAREMODE_ALWAYS: res = true; break;
1732 case Sampler::COMPAREMODE_NEVER: res = false; break;
1737 return res ? 1.0f : 0.0f;
1740 static Vec4 sampleNearest1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1742 int width = access.getWidth();
1744 int x = deFloorFloatToInt32(u)+offset.x();
1746 // Check for CLAMP_TO_BORDER.
1747 if (sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))
1748 return lookupBorder(access.getFormat(), sampler);
1750 int i = wrap(sampler.wrapS, x, width);
1752 return lookup(access, i, offset.y(), 0);
1755 static Vec4 sampleNearest2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1757 int width = access.getWidth();
1758 int height = access.getHeight();
1760 int x = deFloorFloatToInt32(u)+offset.x();
1761 int y = deFloorFloatToInt32(v)+offset.y();
1763 // Check for CLAMP_TO_BORDER.
1764 if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
1765 (sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)))
1766 return lookupBorder(access.getFormat(), sampler);
1768 int i = wrap(sampler.wrapS, x, width);
1769 int j = wrap(sampler.wrapT, y, height);
1771 return lookup(access, i, j, offset.z());
1774 static Vec4 sampleNearest3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
1776 int width = access.getWidth();
1777 int height = access.getHeight();
1778 int depth = access.getDepth();
1780 int x = deFloorFloatToInt32(u)+offset.x();
1781 int y = deFloorFloatToInt32(v)+offset.y();
1782 int z = deFloorFloatToInt32(w)+offset.z();
1784 // Check for CLAMP_TO_BORDER.
1785 if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
1786 (sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)) ||
1787 (sampler.wrapR == Sampler::CLAMP_TO_BORDER && !deInBounds32(z, 0, depth)))
1788 return lookupBorder(access.getFormat(), sampler);
1790 int i = wrap(sampler.wrapS, x, width);
1791 int j = wrap(sampler.wrapT, y, height);
1792 int k = wrap(sampler.wrapR, z, depth);
1794 return lookup(access, i, j, k);
1797 static Vec4 sampleLinear1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1799 int w = access.getWidth();
1801 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1804 int i0 = wrap(sampler.wrapS, x0, w);
1805 int i1 = wrap(sampler.wrapS, x1, w);
1807 float a = deFloatFrac(u-0.5f);
1809 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1810 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1812 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1813 Vec4 p0 = i0UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, offset.y(), 0);
1814 Vec4 p1 = i1UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, offset.y(), 0);
1817 return p0 * (1.0f - a) + p1 * a;
1820 static Vec4 sampleLinear2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1822 int w = access.getWidth();
1823 int h = access.getHeight();
1825 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1827 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
1830 int i0 = wrap(sampler.wrapS, x0, w);
1831 int i1 = wrap(sampler.wrapS, x1, w);
1832 int j0 = wrap(sampler.wrapT, y0, h);
1833 int j1 = wrap(sampler.wrapT, y1, h);
1835 float a = deFloatFrac(u-0.5f);
1836 float b = deFloatFrac(v-0.5f);
1838 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1839 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1840 bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
1841 bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
1843 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1844 Vec4 p00 = (i0UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, offset.z());
1845 Vec4 p10 = (i1UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, offset.z());
1846 Vec4 p01 = (i0UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, offset.z());
1847 Vec4 p11 = (i1UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, offset.z());
1850 return (p00*(1.0f-a)*(1.0f-b)) +
1851 (p10*( a)*(1.0f-b)) +
1852 (p01*(1.0f-a)*( b)) +
1856 static float sampleLinear1DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, const IVec2& offset, bool isFixedPointDepthFormat)
1858 int w = access.getWidth();
1860 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1863 int i0 = wrap(sampler.wrapS, x0, w);
1864 int i1 = wrap(sampler.wrapS, x1, w);
1866 float a = deFloatFrac(u-0.5f);
1868 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1869 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1871 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1872 Vec4 p0Clr = i0UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, offset.y(), 0);
1873 Vec4 p1Clr = i1UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, offset.y(), 0);
1875 // Execute comparisons.
1876 float p0 = execCompare(p0Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
1877 float p1 = execCompare(p1Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
1880 return (p0 * (1.0f - a)) + (p1 * a);
1883 static float sampleLinear2DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, float v, const IVec3& offset, bool isFixedPointDepthFormat)
1885 int w = access.getWidth();
1886 int h = access.getHeight();
1888 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1890 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
1893 int i0 = wrap(sampler.wrapS, x0, w);
1894 int i1 = wrap(sampler.wrapS, x1, w);
1895 int j0 = wrap(sampler.wrapT, y0, h);
1896 int j1 = wrap(sampler.wrapT, y1, h);
1898 float a = deFloatFrac(u-0.5f);
1899 float b = deFloatFrac(v-0.5f);
1901 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1902 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1903 bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
1904 bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
1906 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1907 Vec4 p00Clr = (i0UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, offset.z());
1908 Vec4 p10Clr = (i1UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, offset.z());
1909 Vec4 p01Clr = (i0UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, offset.z());
1910 Vec4 p11Clr = (i1UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, offset.z());
1912 // Execute comparisons.
1913 float p00 = execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
1914 float p10 = execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
1915 float p01 = execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
1916 float p11 = execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
1919 return (p00*(1.0f-a)*(1.0f-b)) +
1920 (p10*( a)*(1.0f-b)) +
1921 (p01*(1.0f-a)*( b)) +
1925 static Vec4 sampleLinear3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
1927 int width = access.getWidth();
1928 int height = access.getHeight();
1929 int depth = access.getDepth();
1931 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1933 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
1935 int z0 = deFloorFloatToInt32(w-0.5f)+offset.z();
1938 int i0 = wrap(sampler.wrapS, x0, width);
1939 int i1 = wrap(sampler.wrapS, x1, width);
1940 int j0 = wrap(sampler.wrapT, y0, height);
1941 int j1 = wrap(sampler.wrapT, y1, height);
1942 int k0 = wrap(sampler.wrapR, z0, depth);
1943 int k1 = wrap(sampler.wrapR, z1, depth);
1945 float a = deFloatFrac(u-0.5f);
1946 float b = deFloatFrac(v-0.5f);
1947 float c = deFloatFrac(w-0.5f);
1949 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, width);
1950 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, width);
1951 bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, height);
1952 bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, height);
1953 bool k0UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k0, 0, depth);
1954 bool k1UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k1, 0, depth);
1956 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1957 Vec4 p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, k0);
1958 Vec4 p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, k0);
1959 Vec4 p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, k0);
1960 Vec4 p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, k0);
1961 Vec4 p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, k1);
1962 Vec4 p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, k1);
1963 Vec4 p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, k1);
1964 Vec4 p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, k1);
1967 return (p000*(1.0f-a)*(1.0f-b)*(1.0f-c)) +
1968 (p100*( a)*(1.0f-b)*(1.0f-c)) +
1969 (p010*(1.0f-a)*( b)*(1.0f-c)) +
1970 (p110*( a)*( b)*(1.0f-c)) +
1971 (p001*(1.0f-a)*(1.0f-b)*( c)) +
1972 (p101*( a)*(1.0f-b)*( c)) +
1973 (p011*(1.0f-a)*( b)*( c)) +
1974 (p111*( a)*( b)*( c));
1977 Vec4 ConstPixelBufferAccess::sample1D (const Sampler& sampler, Sampler::FilterMode filter, float s, int level) const
1979 // check selected layer exists
1980 DE_ASSERT(de::inBounds(level, 0, m_size.y()));
1982 return sample1DOffset(sampler, filter, s, tcu::IVec2(0, level));
1985 Vec4 ConstPixelBufferAccess::sample2D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, int depth) const
1987 // check selected layer exists
1988 DE_ASSERT(de::inBounds(depth, 0, m_size.z()));
1990 return sample2DOffset(sampler, filter, s, t, tcu::IVec3(0, 0, depth));
1993 Vec4 ConstPixelBufferAccess::sample3D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r) const
1995 return sample3DOffset(sampler, filter, s, t, r, tcu::IVec3(0, 0, 0));
1998 Vec4 ConstPixelBufferAccess::sample1DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, const IVec2& offset) const
2000 // check selected layer exists
2001 // \note offset.x is X offset, offset.y is the selected layer
2002 DE_ASSERT(de::inBounds(offset.y(), 0, m_size.y()));
2004 // Non-normalized coordinates.
2007 if (sampler.normalizedCoords)
2008 u = unnormalize(sampler.wrapS, s, m_size.x());
2012 case Sampler::NEAREST: return sampleNearest1D (*this, sampler, u, offset);
2013 case Sampler::LINEAR: return sampleLinear1D (*this, sampler, u, offset);
2015 DE_ASSERT(DE_FALSE);
2020 Vec4 ConstPixelBufferAccess::sample2DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, const IVec3& offset) const
2022 // check selected layer exists
2023 // \note offset.xy is the XY offset, offset.z is the selected layer
2024 DE_ASSERT(de::inBounds(offset.z(), 0, m_size.z()));
2026 // Non-normalized coordinates.
2030 if (sampler.normalizedCoords)
2032 u = unnormalize(sampler.wrapS, s, m_size.x());
2033 v = unnormalize(sampler.wrapT, t, m_size.y());
2038 case Sampler::NEAREST: return sampleNearest2D (*this, sampler, u, v, offset);
2039 case Sampler::LINEAR: return sampleLinear2D (*this, sampler, u, v, offset);
2041 DE_ASSERT(DE_FALSE);
2046 Vec4 ConstPixelBufferAccess::sample3DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r, const IVec3& offset) const
2048 // Non-normalized coordinates.
2053 if (sampler.normalizedCoords)
2055 u = unnormalize(sampler.wrapS, s, m_size.x());
2056 v = unnormalize(sampler.wrapT, t, m_size.y());
2057 w = unnormalize(sampler.wrapR, r, m_size.z());
2062 case Sampler::NEAREST: return sampleNearest3D (*this, sampler, u, v, w, offset);
2063 case Sampler::LINEAR: return sampleLinear3D (*this, sampler, u, v, w, offset);
2065 DE_ASSERT(DE_FALSE);
2070 float ConstPixelBufferAccess::sample1DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, const IVec2& offset) const
2072 // check selected layer exists
2073 // \note offset.x is X offset, offset.y is the selected layer
2074 DE_ASSERT(de::inBounds(offset.y(), 0, m_size.y()));
2076 // Format information for comparison function
2077 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2079 // Non-normalized coordinates.
2082 if (sampler.normalizedCoords)
2083 u = unnormalize(sampler.wrapS, s, m_size.x());
2087 case Sampler::NEAREST: return execCompare(sampleNearest1D(*this, sampler, u, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2088 case Sampler::LINEAR: return sampleLinear1DCompare(*this, sampler, ref, u, offset, isFixedPointDepth);
2090 DE_ASSERT(DE_FALSE);
2095 float ConstPixelBufferAccess::sample2DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, float t, const IVec3& offset) const
2097 // check selected layer exists
2098 // \note offset.xy is XY offset, offset.z is the selected layer
2099 DE_ASSERT(de::inBounds(offset.z(), 0, m_size.z()));
2101 // Format information for comparison function
2102 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2104 // Non-normalized coordinates.
2108 if (sampler.normalizedCoords)
2110 u = unnormalize(sampler.wrapS, s, m_size.x());
2111 v = unnormalize(sampler.wrapT, t, m_size.y());
2116 case Sampler::NEAREST: return execCompare(sampleNearest2D(*this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2117 case Sampler::LINEAR: return sampleLinear2DCompare(*this, sampler, ref, u, v, offset, isFixedPointDepth);
2119 DE_ASSERT(DE_FALSE);
2124 TextureLevel::TextureLevel (void)
2130 TextureLevel::TextureLevel (const TextureFormat& format)
2136 TextureLevel::TextureLevel (const TextureFormat& format, int width, int height, int depth)
2140 setSize(width, height, depth);
2143 TextureLevel::~TextureLevel (void)
2147 void TextureLevel::setStorage (const TextureFormat& format, int width, int height, int depth)
2150 setSize(width, height, depth);
2153 void TextureLevel::setSize (int width, int height, int depth)
2155 int pixelSize = m_format.getPixelSize();
2157 m_size = IVec3(width, height, depth);
2159 m_data.setStorage(m_size.x() * m_size.y() * m_size.z() * pixelSize);
2162 Vec4 sampleLevelArray1D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, int depth, float lod)
2164 return sampleLevelArray1DOffset(levels, numLevels, sampler, s, lod, IVec2(0, depth)); // y-offset in 1D textures is layer selector
2167 Vec4 sampleLevelArray2D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, int depth, float lod)
2169 return sampleLevelArray2DOffset(levels, numLevels, sampler, s, t, lod, IVec3(0, 0, depth)); // z-offset in 2D textures is layer selector
2172 Vec4 sampleLevelArray3D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod)
2174 return sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, IVec3(0, 0, 0));
2177 Vec4 sampleLevelArray1DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float lod, const IVec2& offset)
2179 bool magnified = lod <= sampler.lodThreshold;
2180 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2184 case Sampler::NEAREST: return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2185 case Sampler::LINEAR: return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2187 case Sampler::NEAREST_MIPMAP_NEAREST:
2188 case Sampler::LINEAR_MIPMAP_NEAREST:
2190 int maxLevel = (int)numLevels-1;
2191 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2192 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2194 return levels[level].sample1DOffset(sampler, levelFilter, s, offset);
2197 case Sampler::NEAREST_MIPMAP_LINEAR:
2198 case Sampler::LINEAR_MIPMAP_LINEAR:
2200 int maxLevel = (int)numLevels-1;
2201 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2202 int level1 = de::min(maxLevel, level0 + 1);
2203 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2204 float f = deFloatFrac(lod);
2205 tcu::Vec4 t0 = levels[level0].sample1DOffset(sampler, levelFilter, s, offset);
2206 tcu::Vec4 t1 = levels[level1].sample1DOffset(sampler, levelFilter, s, offset);
2208 return t0*(1.0f - f) + t1*f;
2212 DE_ASSERT(DE_FALSE);
2217 Vec4 sampleLevelArray2DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float lod, const IVec3& offset)
2219 bool magnified = lod <= sampler.lodThreshold;
2220 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2224 case Sampler::NEAREST: return levels[0].sample2DOffset(sampler, filterMode, s, t, offset);
2225 case Sampler::LINEAR: return levels[0].sample2DOffset(sampler, filterMode, s, t, offset);
2227 case Sampler::NEAREST_MIPMAP_NEAREST:
2228 case Sampler::LINEAR_MIPMAP_NEAREST:
2230 int maxLevel = (int)numLevels-1;
2231 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2232 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2234 return levels[level].sample2DOffset(sampler, levelFilter, s, t, offset);
2237 case Sampler::NEAREST_MIPMAP_LINEAR:
2238 case Sampler::LINEAR_MIPMAP_LINEAR:
2240 int maxLevel = (int)numLevels-1;
2241 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2242 int level1 = de::min(maxLevel, level0 + 1);
2243 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2244 float f = deFloatFrac(lod);
2245 tcu::Vec4 t0 = levels[level0].sample2DOffset(sampler, levelFilter, s, t, offset);
2246 tcu::Vec4 t1 = levels[level1].sample2DOffset(sampler, levelFilter, s, t, offset);
2248 return t0*(1.0f - f) + t1*f;
2252 DE_ASSERT(DE_FALSE);
2257 Vec4 sampleLevelArray3DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod, const IVec3& offset)
2259 bool magnified = lod <= sampler.lodThreshold;
2260 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2264 case Sampler::NEAREST: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
2265 case Sampler::LINEAR: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
2267 case Sampler::NEAREST_MIPMAP_NEAREST:
2268 case Sampler::LINEAR_MIPMAP_NEAREST:
2270 int maxLevel = (int)numLevels-1;
2271 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2272 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2274 return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2277 case Sampler::NEAREST_MIPMAP_LINEAR:
2278 case Sampler::LINEAR_MIPMAP_LINEAR:
2280 int maxLevel = (int)numLevels-1;
2281 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2282 int level1 = de::min(maxLevel, level0 + 1);
2283 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2284 float f = deFloatFrac(lod);
2285 tcu::Vec4 t0 = levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2286 tcu::Vec4 t1 = levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2288 return t0*(1.0f - f) + t1*f;
2292 DE_ASSERT(DE_FALSE);
2297 float sampleLevelArray1DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float lod, const IVec2& offset)
2299 bool magnified = lod <= sampler.lodThreshold;
2300 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2304 case Sampler::NEAREST: return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
2305 case Sampler::LINEAR: return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
2307 case Sampler::NEAREST_MIPMAP_NEAREST:
2308 case Sampler::LINEAR_MIPMAP_NEAREST:
2310 int maxLevel = (int)numLevels-1;
2311 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2312 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2314 return levels[level].sample1DCompare(sampler, levelFilter, ref, s, offset);
2317 case Sampler::NEAREST_MIPMAP_LINEAR:
2318 case Sampler::LINEAR_MIPMAP_LINEAR:
2320 int maxLevel = (int)numLevels-1;
2321 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2322 int level1 = de::min(maxLevel, level0 + 1);
2323 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2324 float f = deFloatFrac(lod);
2325 float t0 = levels[level0].sample1DCompare(sampler, levelFilter, ref, s, offset);
2326 float t1 = levels[level1].sample1DCompare(sampler, levelFilter, ref, s, offset);
2328 return t0*(1.0f - f) + t1*f;
2332 DE_ASSERT(DE_FALSE);
2337 float sampleLevelArray2DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float t, float lod, const IVec3& offset)
2339 bool magnified = lod <= sampler.lodThreshold;
2340 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2344 case Sampler::NEAREST: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
2345 case Sampler::LINEAR: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
2347 case Sampler::NEAREST_MIPMAP_NEAREST:
2348 case Sampler::LINEAR_MIPMAP_NEAREST:
2350 int maxLevel = (int)numLevels-1;
2351 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2352 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2354 return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2357 case Sampler::NEAREST_MIPMAP_LINEAR:
2358 case Sampler::LINEAR_MIPMAP_LINEAR:
2360 int maxLevel = (int)numLevels-1;
2361 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2362 int level1 = de::min(maxLevel, level0 + 1);
2363 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2364 float f = deFloatFrac(lod);
2365 float t0 = levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2366 float t1 = levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2368 return t0*(1.0f - f) + t1*f;
2372 DE_ASSERT(DE_FALSE);
2377 static Vec4 fetchGatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2379 DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2381 const int w = src.getWidth();
2382 const int h = src.getHeight();
2383 const float u = unnormalize(sampler.wrapS, s, w);
2384 const float v = unnormalize(sampler.wrapT, t, h);
2385 const int x0 = deFloorFloatToInt32(u-0.5f);
2386 const int y0 = deFloorFloatToInt32(v-0.5f);
2390 for (int i = 0; i < 4; i++)
2392 const int sampleX = wrap(sampler.wrapS, x0 + offsets[i].x(), w);
2393 const int sampleY = wrap(sampler.wrapT, y0 + offsets[i].y(), h);
2396 if (deInBounds32(sampleX, 0, w) && deInBounds32(sampleY, 0, h))
2397 pixel = lookup(src, sampleX, sampleY, depth);
2399 pixel = lookupBorder(src.getFormat(), sampler);
2401 result[i] = pixel[componentNdx];
2407 Vec4 gatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2409 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
2410 DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2412 return fetchGatherArray2DOffsets(src, sampler, s, t, depth, componentNdx, offsets);
2415 Vec4 gatherArray2DOffsetsCompare (const ConstPixelBufferAccess& src, const Sampler& sampler, float ref, float s, float t, int depth, const IVec2 (&offsets)[4])
2417 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
2418 DE_ASSERT(src.getFormat().order == TextureFormat::D || src.getFormat().order == TextureFormat::DS);
2419 DE_ASSERT(sampler.compareChannel == 0);
2421 const bool isFixedPoint = isFixedPointDepthTextureFormat(src.getFormat());
2422 const Vec4 gathered = fetchGatherArray2DOffsets(src, sampler, s, t, depth, 0 /* component 0: depth */, offsets);
2425 for (int i = 0; i < 4; i++)
2426 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
2431 static Vec4 sampleCubeSeamlessNearest (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float s, float t, int depth)
2433 Sampler clampingSampler = sampler;
2434 clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
2435 clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
2436 return faceAccess.sample2D(clampingSampler, Sampler::NEAREST, s, t, depth);
2439 CubeFace selectCubeFace (const Vec3& coords)
2441 const float x = coords.x();
2442 const float y = coords.y();
2443 const float z = coords.z();
2444 const float ax = deFloatAbs(x);
2445 const float ay = deFloatAbs(y);
2446 const float az = deFloatAbs(z);
2448 if (ay < ax && az < ax)
2449 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2450 else if (ax < ay && az < ay)
2451 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2452 else if (ax < az && ay < az)
2453 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2456 // Some of the components are equal. Use tie-breaking rule.
2460 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2462 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2467 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2469 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2474 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2476 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2479 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2483 Vec2 projectToFace (CubeFace face, const Vec3& coord)
2485 const float rx = coord.x();
2486 const float ry = coord.y();
2487 const float rz = coord.z();
2496 case CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break;
2497 case CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break;
2498 case CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break;
2499 case CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break;
2500 case CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break;
2501 case CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break;
2503 DE_ASSERT(DE_FALSE);
2507 s = ((sc / ma) + 1.0f) / 2.0f;
2508 t = ((tc / ma) + 1.0f) / 2.0f;
2513 CubeFaceFloatCoords getCubeFaceCoords (const Vec3& coords)
2515 const CubeFace face = selectCubeFace(coords);
2516 return CubeFaceFloatCoords(face, projectToFace(face, coords));
2519 // Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceIntCoords with face set to the appropriate neighboring face and coords transformed accordingly.
2520 // \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face.
2521 CubeFaceIntCoords remapCubeEdgeCoords (const CubeFaceIntCoords& origCoords, int size)
2523 bool uInBounds = de::inBounds(origCoords.s, 0, size);
2524 bool vInBounds = de::inBounds(origCoords.t, 0, size);
2526 if (uInBounds && vInBounds)
2529 if (!uInBounds && !vInBounds)
2530 return CubeFaceIntCoords(CUBEFACE_LAST, -1, -1);
2532 IVec2 coords(wrap(Sampler::CLAMP_TO_BORDER, origCoords.s, size),
2533 wrap(Sampler::CLAMP_TO_BORDER, origCoords.t, size));
2534 IVec3 canonizedCoords;
2536 // Map the uv coordinates to canonized 3d coordinates.
2538 switch (origCoords.face)
2540 case CUBEFACE_NEGATIVE_X: canonizedCoords = IVec3(0, size-1-coords.y(), coords.x()); break;
2541 case CUBEFACE_POSITIVE_X: canonizedCoords = IVec3(size-1, size-1-coords.y(), size-1-coords.x()); break;
2542 case CUBEFACE_NEGATIVE_Y: canonizedCoords = IVec3(coords.x(), 0, size-1-coords.y()); break;
2543 case CUBEFACE_POSITIVE_Y: canonizedCoords = IVec3(coords.x(), size-1, coords.y()); break;
2544 case CUBEFACE_NEGATIVE_Z: canonizedCoords = IVec3(size-1-coords.x(), size-1-coords.y(), 0); break;
2545 case CUBEFACE_POSITIVE_Z: canonizedCoords = IVec3(coords.x(), size-1-coords.y(), size-1); break;
2546 default: DE_ASSERT(false);
2549 // Find an appropriate face to re-map the coordinates to.
2551 if (canonizedCoords.x() == -1)
2552 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_X, IVec2(canonizedCoords.z(), size-1-canonizedCoords.y()));
2554 if (canonizedCoords.x() == size)
2555 return CubeFaceIntCoords(CUBEFACE_POSITIVE_X, IVec2(size-1-canonizedCoords.z(), size-1-canonizedCoords.y()));
2557 if (canonizedCoords.y() == -1)
2558 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Y, IVec2(canonizedCoords.x(), size-1-canonizedCoords.z()));
2560 if (canonizedCoords.y() == size)
2561 return CubeFaceIntCoords(CUBEFACE_POSITIVE_Y, IVec2(canonizedCoords.x(), canonizedCoords.z()));
2563 if (canonizedCoords.z() == -1)
2564 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Z, IVec2(size-1-canonizedCoords.x(), size-1-canonizedCoords.y()));
2566 if (canonizedCoords.z() == size)
2567 return CubeFaceIntCoords(CUBEFACE_POSITIVE_Z, IVec2(canonizedCoords.x(), size-1-canonizedCoords.y()));
2570 return CubeFaceIntCoords(CUBEFACE_LAST, IVec2(-1));
2573 static void getCubeLinearSamples (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, float u, float v, int depth, Vec4 (&dst)[4])
2575 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2576 int size = faceAccesses[0].getWidth();
2577 int x0 = deFloorFloatToInt32(u-0.5f);
2579 int y0 = deFloorFloatToInt32(v-0.5f);
2581 IVec2 baseSampleCoords[4] =
2588 Vec4 sampleColors[4];
2589 bool hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
2591 // Find correct faces and coordinates for out-of-bounds sample coordinates.
2593 for (int i = 0; i < 4; i++)
2595 CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
2596 hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
2597 if (!hasBothCoordsOutOfBounds[i])
2598 sampleColors[i] = lookup(faceAccesses[coords.face], coords.s, coords.t, depth);
2601 // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
2602 // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
2603 // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
2604 // must have this color as well.
2607 int bothOutOfBoundsNdx = -1;
2608 for (int i = 0; i < 4; i++)
2610 if (hasBothCoordsOutOfBounds[i])
2612 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
2613 bothOutOfBoundsNdx = i;
2616 if (bothOutOfBoundsNdx != -1)
2618 sampleColors[bothOutOfBoundsNdx] = Vec4(0.0f);
2619 for (int i = 0; i < 4; i++)
2620 if (i != bothOutOfBoundsNdx)
2621 sampleColors[bothOutOfBoundsNdx] += sampleColors[i];
2623 sampleColors[bothOutOfBoundsNdx] = sampleColors[bothOutOfBoundsNdx] * (1.0f/3.0f);
2627 for (int i = 0; i < DE_LENGTH_OF_ARRAY(sampleColors); i++)
2628 dst[i] = sampleColors[i];
2631 // \todo [2014-02-19 pyry] Optimize faceAccesses
2632 static Vec4 sampleCubeSeamlessLinear (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float s, float t, int depth)
2634 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2636 int size = faceAccesses[0].getWidth();
2637 // Non-normalized coordinates.
2641 if (sampler.normalizedCoords)
2643 u = unnormalize(sampler.wrapS, s, size);
2644 v = unnormalize(sampler.wrapT, t, size);
2647 // Get sample colors.
2649 Vec4 sampleColors[4];
2650 getCubeLinearSamples(faceAccesses, baseFace, u, v, depth, sampleColors);
2654 float a = deFloatFrac(u-0.5f);
2655 float b = deFloatFrac(v-0.5f);
2657 return (sampleColors[0]*(1.0f-a)*(1.0f-b)) +
2658 (sampleColors[1]*( a)*(1.0f-b)) +
2659 (sampleColors[2]*(1.0f-a)*( b)) +
2660 (sampleColors[3]*( a)*( b));
2663 static Vec4 sampleLevelArrayCubeSeamless (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float s, float t, int depth, float lod)
2665 bool magnified = lod <= sampler.lodThreshold;
2666 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2670 case Sampler::NEAREST:
2671 return sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth);
2673 case Sampler::LINEAR:
2675 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2676 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2677 faceAccesses[i] = faces[i][0];
2679 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
2682 case Sampler::NEAREST_MIPMAP_NEAREST:
2683 case Sampler::LINEAR_MIPMAP_NEAREST:
2685 int maxLevel = (int)numLevels-1;
2686 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2687 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2689 if (levelFilter == Sampler::NEAREST)
2690 return sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
2693 DE_ASSERT(levelFilter == Sampler::LINEAR);
2695 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2696 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2697 faceAccesses[i] = faces[i][level];
2699 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
2703 case Sampler::NEAREST_MIPMAP_LINEAR:
2704 case Sampler::LINEAR_MIPMAP_LINEAR:
2706 int maxLevel = (int)numLevels-1;
2707 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2708 int level1 = de::min(maxLevel, level0 + 1);
2709 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2710 float f = deFloatFrac(lod);
2714 if (levelFilter == Sampler::NEAREST)
2716 t0 = sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
2717 t1 = sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
2721 DE_ASSERT(levelFilter == Sampler::LINEAR);
2723 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
2724 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
2725 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2727 faceAccesses0[i] = faces[i][level0];
2728 faceAccesses1[i] = faces[i][level1];
2731 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
2732 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
2735 return t0*(1.0f - f) + t1*f;
2739 DE_ASSERT(DE_FALSE);
2744 static float sampleCubeSeamlessNearestCompare (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float ref, float s, float t, int depth = 0)
2746 Sampler clampingSampler = sampler;
2747 clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
2748 clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
2749 return faceAccess.sample2DCompare(clampingSampler, Sampler::NEAREST, ref, s, t, IVec3(0, 0, depth));
2752 static float sampleCubeSeamlessLinearCompare (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float ref, float s, float t)
2754 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2756 int size = faceAccesses[0].getWidth();
2757 // Non-normalized coordinates.
2761 if (sampler.normalizedCoords)
2763 u = unnormalize(sampler.wrapS, s, size);
2764 v = unnormalize(sampler.wrapT, t, size);
2767 int x0 = deFloorFloatToInt32(u-0.5f);
2769 int y0 = deFloorFloatToInt32(v-0.5f);
2771 IVec2 baseSampleCoords[4] =
2779 bool hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
2781 // Find correct faces and coordinates for out-of-bounds sample coordinates.
2783 for (int i = 0; i < 4; i++)
2785 CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
2786 hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
2788 if (!hasBothCoordsOutOfBounds[i])
2790 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
2792 sampleRes[i] = execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2796 // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
2797 // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
2798 // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
2799 // must have this color as well.
2802 int bothOutOfBoundsNdx = -1;
2803 for (int i = 0; i < 4; i++)
2805 if (hasBothCoordsOutOfBounds[i])
2807 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
2808 bothOutOfBoundsNdx = i;
2811 if (bothOutOfBoundsNdx != -1)
2813 sampleRes[bothOutOfBoundsNdx] = 0.0f;
2814 for (int i = 0; i < 4; i++)
2815 if (i != bothOutOfBoundsNdx)
2816 sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
2818 sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0f/3.0f);
2824 float a = deFloatFrac(u-0.5f);
2825 float b = deFloatFrac(v-0.5f);
2827 return (sampleRes[0]*(1.0f-a)*(1.0f-b)) +
2828 (sampleRes[1]*( a)*(1.0f-b)) +
2829 (sampleRes[2]*(1.0f-a)*( b)) +
2830 (sampleRes[3]*( a)*( b));
2833 static float sampleLevelArrayCubeSeamlessCompare (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
2835 bool magnified = lod <= sampler.lodThreshold;
2836 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2840 case Sampler::NEAREST:
2841 return sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
2843 case Sampler::LINEAR:
2845 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2846 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2847 faceAccesses[i] = faces[i][0];
2849 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
2852 case Sampler::NEAREST_MIPMAP_NEAREST:
2853 case Sampler::LINEAR_MIPMAP_NEAREST:
2855 int maxLevel = (int)numLevels-1;
2856 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2857 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2859 if (levelFilter == Sampler::NEAREST)
2860 return sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
2863 DE_ASSERT(levelFilter == Sampler::LINEAR);
2865 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2866 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2867 faceAccesses[i] = faces[i][level];
2869 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
2873 case Sampler::NEAREST_MIPMAP_LINEAR:
2874 case Sampler::LINEAR_MIPMAP_LINEAR:
2876 int maxLevel = (int)numLevels-1;
2877 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2878 int level1 = de::min(maxLevel, level0 + 1);
2879 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2880 float f = deFloatFrac(lod);
2884 if (levelFilter == Sampler::NEAREST)
2886 t0 = sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
2887 t1 = sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
2891 DE_ASSERT(levelFilter == Sampler::LINEAR);
2893 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
2894 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
2895 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2897 faceAccesses0[i] = faces[i][level0];
2898 faceAccesses1[i] = faces[i][level1];
2901 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
2902 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
2905 return t0*(1.0f - f) + t1*f;
2909 DE_ASSERT(DE_FALSE);
2914 // Cube map array sampling
2916 static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face)
2918 const ConstPixelBufferAccess& level = levels[levelNdx];
2919 const int depth = (slice * 6) + getCubeArrayFaceIndex(face);
2921 return getSubregion(level, 0, 0, depth, level.getWidth(), level.getHeight(), 1);
2924 static Vec4 sampleCubeArraySeamless (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float s, float t, float lod)
2926 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face);
2927 const bool magnified = lod <= sampler.lodThreshold;
2928 const Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2932 case Sampler::NEAREST:
2933 return sampleCubeSeamlessNearest(levels[0], sampler, s, t, faceDepth);
2935 case Sampler::LINEAR:
2937 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2938 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2939 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
2941 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
2944 case Sampler::NEAREST_MIPMAP_NEAREST:
2945 case Sampler::LINEAR_MIPMAP_NEAREST:
2947 int maxLevel = (int)numLevels-1;
2948 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2949 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2951 if (levelFilter == Sampler::NEAREST)
2952 return sampleCubeSeamlessNearest(levels[level], sampler, s, t, faceDepth);
2955 DE_ASSERT(levelFilter == Sampler::LINEAR);
2957 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2958 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2959 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
2961 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
2965 case Sampler::NEAREST_MIPMAP_LINEAR:
2966 case Sampler::LINEAR_MIPMAP_LINEAR:
2968 int maxLevel = (int)numLevels-1;
2969 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2970 int level1 = de::min(maxLevel, level0 + 1);
2971 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2972 float f = deFloatFrac(lod);
2976 if (levelFilter == Sampler::NEAREST)
2978 t0 = sampleCubeSeamlessNearest(levels[level0], sampler, s, t, faceDepth);
2979 t1 = sampleCubeSeamlessNearest(levels[level1], sampler, s, t, faceDepth);
2983 DE_ASSERT(levelFilter == Sampler::LINEAR);
2985 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
2986 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
2987 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2989 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
2990 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
2993 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, 0);
2994 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, 0);
2997 return t0*(1.0f - f) + t1*f;
3001 DE_ASSERT(DE_FALSE);
3006 static float sampleCubeArraySeamlessCompare (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
3008 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face);
3009 const bool magnified = lod <= sampler.lodThreshold;
3010 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
3014 case Sampler::NEAREST:
3015 return sampleCubeSeamlessNearestCompare(levels[0], sampler, ref, s, t, faceDepth);
3017 case Sampler::LINEAR:
3019 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3020 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3021 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
3023 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3026 case Sampler::NEAREST_MIPMAP_NEAREST:
3027 case Sampler::LINEAR_MIPMAP_NEAREST:
3029 int maxLevel = (int)numLevels-1;
3030 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3031 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3033 if (levelFilter == Sampler::NEAREST)
3034 return sampleCubeSeamlessNearestCompare(levels[level], sampler, ref, s, t, faceDepth);
3037 DE_ASSERT(levelFilter == Sampler::LINEAR);
3039 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3040 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3041 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
3043 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3047 case Sampler::NEAREST_MIPMAP_LINEAR:
3048 case Sampler::LINEAR_MIPMAP_LINEAR:
3050 int maxLevel = (int)numLevels-1;
3051 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3052 int level1 = de::min(maxLevel, level0 + 1);
3053 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3054 float f = deFloatFrac(lod);
3058 if (levelFilter == Sampler::NEAREST)
3060 t0 = sampleCubeSeamlessNearestCompare(levels[level0], sampler, ref, s, t, faceDepth);
3061 t1 = sampleCubeSeamlessNearestCompare(levels[level1], sampler, ref, s, t, faceDepth);
3065 DE_ASSERT(levelFilter == Sampler::LINEAR);
3067 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3068 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3069 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3071 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
3072 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
3075 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
3076 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
3079 return t0*(1.0f - f) + t1*f;
3083 DE_ASSERT(DE_FALSE);
3088 inline int computeMipPyramidLevels (int size)
3090 return deLog2Floor32(size)+1;
3093 inline int computeMipPyramidLevels (int width, int height)
3095 return deLog2Floor32(de::max(width, height))+1;
3098 inline int computeMipPyramidLevels (int width, int height, int depth)
3100 return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
3103 inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx)
3105 return de::max(baseLevelSize >> levelNdx, 1);
3108 // TextureLevelPyramid
3110 TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels)
3112 , m_data (numLevels)
3113 , m_access (numLevels)
3117 TextureLevelPyramid::TextureLevelPyramid (const TextureLevelPyramid& other)
3118 : m_format (other.m_format)
3119 , m_data (other.getNumLevels())
3120 , m_access (other.getNumLevels())
3122 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3124 if (!other.isLevelEmpty(levelNdx))
3126 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
3128 m_data[levelNdx] = other.m_data[levelNdx];
3129 m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
3134 TextureLevelPyramid& TextureLevelPyramid::operator= (const TextureLevelPyramid& other)
3139 m_format = other.m_format;
3140 m_data.resize(other.getNumLevels());
3141 m_access.resize(other.getNumLevels());
3143 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3145 if (!other.isLevelEmpty(levelNdx))
3147 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
3149 m_data[levelNdx] = other.m_data[levelNdx];
3150 m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
3152 else if (!isLevelEmpty(levelNdx))
3153 clearLevel(levelNdx);
3159 TextureLevelPyramid::~TextureLevelPyramid (void)
3163 void TextureLevelPyramid::allocLevel (int levelNdx, int width, int height, int depth)
3165 const int size = m_format.getPixelSize()*width*height*depth;
3167 DE_ASSERT(isLevelEmpty(levelNdx));
3169 m_data[levelNdx].setStorage(size);
3170 m_access[levelNdx] = PixelBufferAccess(m_format, width, height, depth, m_data[levelNdx].getPtr());
3173 void TextureLevelPyramid::clearLevel (int levelNdx)
3175 DE_ASSERT(!isLevelEmpty(levelNdx));
3177 m_data[levelNdx].clear();
3178 m_access[levelNdx] = PixelBufferAccess();
3183 Texture1D::Texture1D (const TextureFormat& format, int width)
3184 : TextureLevelPyramid (format, computeMipPyramidLevels(width))
3186 , m_view (getNumLevels(), getLevels())
3190 Texture1D::Texture1D (const Texture1D& other)
3191 : TextureLevelPyramid (other)
3192 , m_width (other.m_width)
3193 , m_view (getNumLevels(), getLevels())
3197 Texture1D& Texture1D::operator= (const Texture1D& other)
3202 TextureLevelPyramid::operator=(other);
3204 m_width = other.m_width;
3205 m_view = Texture1DView(getNumLevels(), getLevels());
3210 Texture1D::~Texture1D (void)
3214 void Texture1D::allocLevel (int levelNdx)
3216 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3218 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3220 TextureLevelPyramid::allocLevel(levelNdx, width, 1, 1);
3225 Texture2D::Texture2D (const TextureFormat& format, int width, int height)
3226 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height))
3229 , m_view (getNumLevels(), getLevels())
3233 Texture2D::Texture2D (const Texture2D& other)
3234 : TextureLevelPyramid (other)
3235 , m_width (other.m_width)
3236 , m_height (other.m_height)
3237 , m_view (getNumLevels(), getLevels())
3241 Texture2D& Texture2D::operator= (const Texture2D& other)
3246 TextureLevelPyramid::operator=(other);
3248 m_width = other.m_width;
3249 m_height = other.m_height;
3250 m_view = Texture2DView(getNumLevels(), getLevels());
3255 Texture2D::~Texture2D (void)
3259 void Texture2D::allocLevel (int levelNdx)
3261 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3263 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3264 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3266 TextureLevelPyramid::allocLevel(levelNdx, width, height, 1);
3271 TextureCubeView::TextureCubeView (void)
3274 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3275 m_levels[ndx] = DE_NULL;
3278 TextureCubeView::TextureCubeView (int numLevels, const ConstPixelBufferAccess* const (&levels) [CUBEFACE_LAST])
3279 : m_numLevels(numLevels)
3281 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3282 m_levels[ndx] = levels[ndx];
3285 tcu::Vec4 TextureCubeView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3287 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3289 // Computes (face, s, t).
3290 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3291 if (sampler.seamlessCubeMap)
3292 return sampleLevelArrayCubeSeamless(m_levels, m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod);
3294 return sampleLevelArray2D(m_levels[coords.face], m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod);
3297 float TextureCubeView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3299 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3301 // Computes (face, s, t).
3302 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3303 if (sampler.seamlessCubeMap)
3304 return sampleLevelArrayCubeSeamlessCompare(m_levels, m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod);
3306 return sampleLevelArray2DCompare(m_levels[coords.face], m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, 0));
3309 Vec4 TextureCubeView::gather (const Sampler& sampler, float s, float t, float r, int componentNdx) const
3311 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3313 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3314 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3315 faceAccesses[i] = m_levels[i][0];
3317 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3318 const int size = faceAccesses[0].getWidth();
3319 // Non-normalized coordinates.
3323 if (sampler.normalizedCoords)
3325 u = unnormalize(sampler.wrapS, coords.s, size);
3326 v = unnormalize(sampler.wrapT, coords.t, size);
3329 Vec4 sampleColors[4];
3330 getCubeLinearSamples(faceAccesses, coords.face, u, v, 0, sampleColors);
3332 const int sampleIndices[4] = { 2, 3, 1, 0 }; // \note Gather returns the samples in a non-obvious order.
3334 for (int i = 0; i < 4; i++)
3335 result[i] = sampleColors[sampleIndices[i]][componentNdx];
3340 Vec4 TextureCubeView::gatherCompare (const Sampler& sampler, float ref, float s, float t, float r) const
3342 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3343 DE_ASSERT(m_levels[0][0].getFormat().order == TextureFormat::D || m_levels[0][0].getFormat().order == TextureFormat::DS);
3344 DE_ASSERT(sampler.compareChannel == 0);
3346 Sampler noCompareSampler = sampler;
3347 noCompareSampler.compare = Sampler::COMPAREMODE_NONE;
3349 const Vec4 gathered = gather(noCompareSampler, s, t, r, 0 /* component 0: depth */);
3350 const bool isFixedPoint = isFixedPointDepthTextureFormat(m_levels[0][0].getFormat());
3352 for (int i = 0; i < 4; i++)
3353 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
3360 TextureCube::TextureCube (const TextureFormat& format, int size)
3364 const int numLevels = computeMipPyramidLevels(m_size);
3365 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3367 for (int face = 0; face < CUBEFACE_LAST; face++)
3369 m_data[face].resize(numLevels);
3370 m_access[face].resize(numLevels);
3371 levels[face] = &m_access[face][0];
3374 m_view = TextureCubeView(numLevels, levels);
3377 TextureCube::TextureCube (const TextureCube& other)
3378 : m_format (other.m_format)
3379 , m_size (other.m_size)
3381 const int numLevels = computeMipPyramidLevels(m_size);
3382 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3384 for (int face = 0; face < CUBEFACE_LAST; face++)
3386 m_data[face].resize(numLevels);
3387 m_access[face].resize(numLevels);
3388 levels[face] = &m_access[face][0];
3391 m_view = TextureCubeView(numLevels, levels);
3393 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3395 for (int face = 0; face < CUBEFACE_LAST; face++)
3397 if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3399 allocLevel((CubeFace)face, levelNdx);
3400 copy(getLevelFace(levelNdx, (CubeFace)face),
3401 other.getLevelFace(levelNdx, (CubeFace)face));
3407 TextureCube& TextureCube::operator= (const TextureCube& other)
3412 const int numLevels = computeMipPyramidLevels(other.m_size);
3413 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3415 for (int face = 0; face < CUBEFACE_LAST; face++)
3417 m_data[face].resize(numLevels);
3418 m_access[face].resize(numLevels);
3419 levels[face] = &m_access[face][0];
3422 m_format = other.m_format;
3423 m_size = other.m_size;
3424 m_view = TextureCubeView(numLevels, levels);
3426 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3428 for (int face = 0; face < CUBEFACE_LAST; face++)
3430 if (!isLevelEmpty((CubeFace)face, levelNdx))
3431 clearLevel((CubeFace)face, levelNdx);
3433 if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3435 allocLevel((CubeFace)face, levelNdx);
3436 copy(getLevelFace(levelNdx, (CubeFace)face),
3437 other.getLevelFace(levelNdx, (CubeFace)face));
3445 TextureCube::~TextureCube (void)
3449 void TextureCube::allocLevel (tcu::CubeFace face, int levelNdx)
3451 const int size = getMipPyramidLevelSize(m_size, levelNdx);
3452 const int dataSize = m_format.getPixelSize()*size*size;
3453 DE_ASSERT(isLevelEmpty(face, levelNdx));
3455 m_data[face][levelNdx].setStorage(dataSize);
3456 m_access[face][levelNdx] = PixelBufferAccess(m_format, size, size, 1, m_data[face][levelNdx].getPtr());
3459 void TextureCube::clearLevel (tcu::CubeFace face, int levelNdx)
3461 DE_ASSERT(!isLevelEmpty(face, levelNdx));
3462 m_data[face][levelNdx].clear();
3463 m_access[face][levelNdx] = PixelBufferAccess();
3466 // Texture1DArrayView
3468 Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3469 : m_numLevels (numLevels)
3474 inline int Texture1DArrayView::selectLayer (float r) const
3476 DE_ASSERT(m_numLevels > 0 && m_levels);
3477 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getHeight()-1);
3480 Vec4 Texture1DArrayView::sample (const Sampler& sampler, float s, float t, float lod) const
3482 return sampleLevelArray1D(m_levels, m_numLevels, sampler, s, selectLayer(t), lod);
3485 Vec4 Texture1DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float lod, deInt32 offset) const
3487 return sampleLevelArray1DOffset(m_levels, m_numLevels, sampler, s, lod, IVec2(offset, selectLayer(t)));
3490 float Texture1DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float lod) const
3492 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(0, selectLayer(t)));
3495 float Texture1DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float lod, deInt32 offset) const
3497 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(offset, selectLayer(t)));
3500 // Texture2DArrayView
3502 Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3503 : m_numLevels (numLevels)
3508 inline int Texture2DArrayView::selectLayer (float r) const
3510 DE_ASSERT(m_numLevels > 0 && m_levels);
3511 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getDepth()-1);
3514 Vec4 Texture2DArrayView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3516 return sampleLevelArray2D(m_levels, m_numLevels, sampler, s, t, selectLayer(r), lod);
3519 float Texture2DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3521 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(0, 0, selectLayer(r)));
3524 Vec4 Texture2DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float r, float lod, const IVec2& offset) const
3526 return sampleLevelArray2DOffset(m_levels, m_numLevels, sampler, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
3529 float Texture2DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float r, float lod, const IVec2& offset) const
3531 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
3534 Vec4 Texture2DArrayView::gatherOffsets (const Sampler& sampler, float s, float t, float r, int componentNdx, const IVec2 (&offsets)[4]) const
3536 return gatherArray2DOffsets(m_levels[0], sampler, s, t, selectLayer(r), componentNdx, offsets);
3539 Vec4 Texture2DArrayView::gatherOffsetsCompare (const Sampler& sampler, float ref, float s, float t, float r, const IVec2 (&offsets)[4]) const
3541 return gatherArray2DOffsetsCompare(m_levels[0], sampler, ref, s, t, selectLayer(r), offsets);
3546 Texture1DArray::Texture1DArray (const TextureFormat& format, int width, int numLayers)
3547 : TextureLevelPyramid (format, computeMipPyramidLevels(width))
3549 , m_numLayers (numLayers)
3550 , m_view (getNumLevels(), getLevels())
3554 Texture1DArray::Texture1DArray (const Texture1DArray& other)
3555 : TextureLevelPyramid (other)
3556 , m_width (other.m_width)
3557 , m_numLayers (other.m_numLayers)
3558 , m_view (getNumLevels(), getLevels())
3562 Texture1DArray& Texture1DArray::operator= (const Texture1DArray& other)
3567 TextureLevelPyramid::operator=(other);
3569 m_width = other.m_width;
3570 m_numLayers = other.m_numLayers;
3571 m_view = Texture1DArrayView(getNumLevels(), getLevels());
3576 Texture1DArray::~Texture1DArray (void)
3580 void Texture1DArray::allocLevel (int levelNdx)
3582 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3584 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3586 TextureLevelPyramid::allocLevel(levelNdx, width, m_numLayers, 1);
3591 Texture2DArray::Texture2DArray (const TextureFormat& format, int width, int height, int numLayers)
3592 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height))
3595 , m_numLayers (numLayers)
3596 , m_view (getNumLevels(), getLevels())
3600 Texture2DArray::Texture2DArray (const Texture2DArray& other)
3601 : TextureLevelPyramid (other)
3602 , m_width (other.m_width)
3603 , m_height (other.m_height)
3604 , m_numLayers (other.m_numLayers)
3605 , m_view (getNumLevels(), getLevels())
3609 Texture2DArray& Texture2DArray::operator= (const Texture2DArray& other)
3614 TextureLevelPyramid::operator=(other);
3616 m_width = other.m_width;
3617 m_height = other.m_height;
3618 m_numLayers = other.m_numLayers;
3619 m_view = Texture2DArrayView(getNumLevels(), getLevels());
3624 Texture2DArray::~Texture2DArray (void)
3628 void Texture2DArray::allocLevel (int levelNdx)
3630 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3632 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3633 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3635 TextureLevelPyramid::allocLevel(levelNdx, width, height, m_numLayers);
3640 Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels)
3641 : m_numLevels (numLevels)
3648 Texture3D::Texture3D (const TextureFormat& format, int width, int height, int depth)
3649 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height, depth))
3653 , m_view (getNumLevels(), getLevels())
3657 Texture3D::Texture3D (const Texture3D& other)
3658 : TextureLevelPyramid (other)
3659 , m_width (other.m_width)
3660 , m_height (other.m_height)
3661 , m_depth (other.m_depth)
3662 , m_view (getNumLevels(), getLevels())
3666 Texture3D& Texture3D::operator= (const Texture3D& other)
3671 TextureLevelPyramid::operator=(other);
3673 m_width = other.m_width;
3674 m_height = other.m_height;
3675 m_depth = other.m_depth;
3676 m_view = Texture3DView(getNumLevels(), getLevels());
3681 Texture3D::~Texture3D (void)
3685 void Texture3D::allocLevel (int levelNdx)
3687 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3689 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3690 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3691 const int depth = getMipPyramidLevelSize(m_depth, levelNdx);
3693 TextureLevelPyramid::allocLevel(levelNdx, width, height, depth);
3696 // TextureCubeArrayView
3698 TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels)
3699 : m_numLevels (numLevels)
3704 inline int TextureCubeArrayView::selectLayer (float q) const
3706 DE_ASSERT(m_numLevels > 0 && m_levels);
3707 DE_ASSERT((m_levels[0].getDepth() % 6) == 0);
3709 return de::clamp(deFloorFloatToInt32(q + 0.5f), 0, (m_levels[0].getDepth() / 6)-1);
3712 tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const
3714 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3715 const int layer = selectLayer(q);
3716 const int faceDepth = (layer * 6) + getCubeArrayFaceIndex(coords.face);
3718 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3720 if (sampler.seamlessCubeMap)
3721 return sampleCubeArraySeamless(m_levels, m_numLevels, layer, coords.face, sampler, coords.s, coords.t, lod);
3723 return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod);
3726 float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const
3728 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3729 const int layer = selectLayer(q);
3730 const int faceDepth = (layer * 6) + getCubeArrayFaceIndex(coords.face);
3732 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3734 if (sampler.seamlessCubeMap)
3735 return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, layer, coords.face, sampler, ref, coords.s, coords.t, lod);
3737 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth));
3742 TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int depth)
3743 : TextureLevelPyramid (format, computeMipPyramidLevels(size))
3746 , m_view (getNumLevels(), getLevels())
3748 DE_ASSERT(m_depth % 6 == 0);
3751 TextureCubeArray::TextureCubeArray (const TextureCubeArray& other)
3752 : TextureLevelPyramid (other)
3753 , m_size (other.m_size)
3754 , m_depth (other.m_depth)
3755 , m_view (getNumLevels(), getLevels())
3757 DE_ASSERT(m_depth % 6 == 0);
3760 TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
3765 TextureLevelPyramid::operator=(other);
3767 m_size = other.m_size;
3768 m_depth = other.m_depth;
3769 m_view = TextureCubeArrayView(getNumLevels(), getLevels());
3771 DE_ASSERT(m_depth % 6 == 0);
3776 TextureCubeArray::~TextureCubeArray (void)
3780 void TextureCubeArray::allocLevel (int levelNdx)
3782 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3784 const int size = getMipPyramidLevelSize(m_size, levelNdx);
3786 TextureLevelPyramid::allocLevel(levelNdx, size, size, m_depth);
3789 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order)
3791 const char* const orderStrings[] =
3818 return str << de::getSizedArrayElement<TextureFormat::CHANNELORDER_LAST>(orderStrings, order);
3821 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelType type)
3823 const char* const typeStrings[] =
3839 "SNORM_INT_1010102_REV",
3840 "UNORM_INT_1010102_REV",
3842 "UNSIGNED_SHORT_565",
3843 "UNSIGNED_SHORT_4444",
3844 "UNSIGNED_SHORT_5551",
3845 "SIGNED_INT_1010102_REV",
3846 "UNSIGNED_INT_1010102_REV",
3847 "UNSIGNED_INT_11F_11F_10F_REV",
3848 "UNSIGNED_INT_999_E5_REV",
3849 "UNSIGNED_INT_16_8_8",
3850 "UNSIGNED_INT_24_8",
3851 "UNSIGNED_INT_24_8_REV",
3862 "FLOAT_UNSIGNED_INT_24_8_REV",
3867 return str << de::getSizedArrayElement<TextureFormat::CHANNELTYPE_LAST>(typeStrings, type);
3870 std::ostream& operator<< (std::ostream& str, CubeFace face)
3874 case CUBEFACE_NEGATIVE_X: return str << "CUBEFACE_NEGATIVE_X";
3875 case CUBEFACE_POSITIVE_X: return str << "CUBEFACE_POSITIVE_X";
3876 case CUBEFACE_NEGATIVE_Y: return str << "CUBEFACE_NEGATIVE_Y";
3877 case CUBEFACE_POSITIVE_Y: return str << "CUBEFACE_POSITIVE_Y";
3878 case CUBEFACE_NEGATIVE_Z: return str << "CUBEFACE_NEGATIVE_Z";
3879 case CUBEFACE_POSITIVE_Z: return str << "CUBEFACE_POSITIVE_Z";
3880 case CUBEFACE_LAST: return str << "CUBEFACE_LAST";
3881 default: return str << "UNKNOWN(" << (int)face << ")";
3885 std::ostream& operator<< (std::ostream& str, TextureFormat format)
3887 return str << format.order << ", " << format.type << "";
3890 std::ostream& operator<< (std::ostream& str, const ConstPixelBufferAccess& access)
3892 return str << "format = (" << access.getFormat() << "), size = "
3893 << access.getWidth() << " x " << access.getHeight() << " x " << access.getDepth()
3894 << ", pitch = " << access.getRowPitch() << " / " << access.getSlicePitch();