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