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