tcuTexture.cpp revision 3c827367444ee418f129b2c238299f49d3264554
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 37namespace tcu 38{ 39 40// \note No denorm support, no sign. 41typedef Float<deUint32, 5, 6, 15, 0> Float11; 42typedef Float<deUint32, 5, 5, 15, 0> Float10; 43 44namespace 45{ 46 47// Optimized getters for common formats. 48// \todo [2012-11-14 pyry] Use intrinsics if available. 49 50inline Vec4 readRGBA8888Float (const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, ptr[3]/255.0f); } 51inline Vec4 readRGB888Float (const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, 1.0f); } 52inline IVec4 readRGBA8888Int (const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], ptr[3]); } 53inline IVec4 readRGB888Int (const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], 0xff); } 54 55// Optimized setters. 56 57inline 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 65inline 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 72inline 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 80inline 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 87enum 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? 100template <typename T> 101inline 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 128const 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 170const 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 211int 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 235int 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 261inline 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 285inline 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 309void 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 332template <typename T, typename S> 333static 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 346void 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 367inline float channelToNormFloat (deUint32 src, int bits) 368{ 369 deUint32 maxVal = (1u << bits) - 1; 370 return (float)src / (float)maxVal; 371} 372 373inline 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 380inline deUint32 uintToChannel (deUint32 src, int bits) 381{ 382 deUint32 maxVal = (1u << bits) - 1; 383 return de::min(maxVal, src); 384} 385 386deUint32 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 415tcu::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. */ 436int 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 523ConstPixelBufferAccess::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 533ConstPixelBufferAccess::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 544ConstPixelBufferAccess::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 555ConstPixelBufferAccess::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 566PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data) 567 : ConstPixelBufferAccess(format, width, height, depth, data) 568{ 569} 570 571PixelBufferAccess::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 576PixelBufferAccess::PixelBufferAccess (TextureLevel& level) 577 : ConstPixelBufferAccess(level) 578{ 579} 580 581void PixelBufferAccess::setPixels (const void* buf, int bufSize) const 582{ 583 DE_ASSERT(bufSize == getDataSize()); 584 deMemcpy(getDataPtr(), buf, bufSize); 585} 586 587Vec4 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 672IVec4 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 746template<> 747Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const 748{ 749 return getPixel(x, y, z); 750} 751 752template<> 753IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const 754{ 755 return getPixelInt(x, y, z); 756} 757 758template<> 759UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const 760{ 761 return getPixelUint(x, y, z); 762} 763 764float 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 804int 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 844void 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 940void 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 1002void 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 1039void 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 1083static inline int imod (int a, int b) 1084{ 1085 int m = a % b; 1086 return m < 0 ? m + b : m; 1087} 1088 1089static 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. 1095static 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 1110static 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. 1139static 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 1161static inline bool isSRGB (TextureFormat format) 1162{ 1163 return format.order == TextureFormat::sRGB || format.order == TextureFormat::sRGBA; 1164} 1165 1166static 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. 1196static 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 1202static 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 1226static 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 1240static 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 1255static 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 1274static 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 1293static 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 1316static 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 1339static 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 1362static 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 1385static 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 1421static 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 1457static 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 1484static 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 1526static 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 1578static 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 1630Vec4 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 1650Vec4 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 1674Vec4 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 1694Vec4 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 1718float 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 1741float 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 1768Vec4 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 1792Vec4 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 1816TextureLevel::TextureLevel (void) 1817 : m_format () 1818 , m_width (0) 1819 , m_height (0) 1820 , m_depth (0) 1821{ 1822} 1823 1824TextureLevel::TextureLevel (const TextureFormat& format) 1825 : m_format (format) 1826 , m_width (0) 1827 , m_height (0) 1828 , m_depth (0) 1829{ 1830} 1831 1832TextureLevel::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 1841TextureLevel::~TextureLevel (void) 1842{ 1843} 1844 1845void TextureLevel::setStorage (const TextureFormat& format, int width, int height, int depth) 1846{ 1847 m_format = format; 1848 setSize(width, height, depth); 1849} 1850 1851void 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 1862Vec4 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 1902Vec4 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 1942Vec4 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 1982Vec4 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 2022Vec4 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 2062Vec4 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 2102float 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 2142float 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 2182Vec4 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 2209Vec4 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 2227static 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 2235CubeFace 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 2279Vec2 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 2309CubeFaceFloatCoords 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. 2317CubeFaceIntCoords 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 2369static 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 2428static 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 2459static 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 2540static 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 2548static 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 2629static 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 2712static inline int getCubeArrayFaceIndex (CubeFace face) 2713{ 2714 DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST); 2715 2716 switch (face) 2717 { 2718 case CUBEFACE_POSITIVE_X: return 0; 2719 case CUBEFACE_NEGATIVE_X: return 1; 2720 case CUBEFACE_POSITIVE_Y: return 2; 2721 case CUBEFACE_NEGATIVE_Y: return 3; 2722 case CUBEFACE_POSITIVE_Z: return 4; 2723 case CUBEFACE_NEGATIVE_Z: return 5; 2724 2725 default: 2726 return -1; 2727 } 2728} 2729 2730static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face) 2731{ 2732 const ConstPixelBufferAccess& level = levels[levelNdx]; 2733 const int depth = (slice * 6) + getCubeArrayFaceIndex(face); 2734 2735 return getSubregion(level, 0, 0, depth, level.getWidth(), level.getHeight(), 1); 2736} 2737 2738static Vec4 sampleCubeArraySeamless (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float s, float t, float lod) 2739{ 2740 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face); 2741 const bool magnified = lod <= sampler.lodThreshold; 2742 const Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter; 2743 2744 switch (filterMode) 2745 { 2746 case Sampler::NEAREST: 2747 return sampleCubeSeamlessNearest(levels[0], sampler, s, t, faceDepth); 2748 2749 case Sampler::LINEAR: 2750 { 2751 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST]; 2752 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 2753 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i); 2754 2755 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0); 2756 } 2757 2758 case Sampler::NEAREST_MIPMAP_NEAREST: 2759 case Sampler::LINEAR_MIPMAP_NEAREST: 2760 { 2761 int maxLevel = (int)numLevels-1; 2762 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel); 2763 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST; 2764 2765 if (levelFilter == Sampler::NEAREST) 2766 return sampleCubeSeamlessNearest(levels[level], sampler, s, t, faceDepth); 2767 else 2768 { 2769 DE_ASSERT(levelFilter == Sampler::LINEAR); 2770 2771 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST]; 2772 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 2773 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i); 2774 2775 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0); 2776 } 2777 } 2778 2779 case Sampler::NEAREST_MIPMAP_LINEAR: 2780 case Sampler::LINEAR_MIPMAP_LINEAR: 2781 { 2782 int maxLevel = (int)numLevels-1; 2783 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel); 2784 int level1 = de::min(maxLevel, level0 + 1); 2785 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST; 2786 float f = deFloatFrac(lod); 2787 Vec4 t0; 2788 Vec4 t1; 2789 2790 if (levelFilter == Sampler::NEAREST) 2791 { 2792 t0 = sampleCubeSeamlessNearest(levels[level0], sampler, s, t, faceDepth); 2793 t1 = sampleCubeSeamlessNearest(levels[level1], sampler, s, t, faceDepth); 2794 } 2795 else 2796 { 2797 DE_ASSERT(levelFilter == Sampler::LINEAR); 2798 2799 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST]; 2800 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST]; 2801 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 2802 { 2803 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i); 2804 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i); 2805 } 2806 2807 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, 0); 2808 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, 0); 2809 } 2810 2811 return t0*(1.0f - f) + t1*f; 2812 } 2813 2814 default: 2815 DE_ASSERT(DE_FALSE); 2816 return Vec4(0.0f); 2817 } 2818} 2819 2820static float sampleCubeArraySeamlessCompare (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod) 2821{ 2822 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face); 2823 const bool magnified = lod <= sampler.lodThreshold; 2824 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter; 2825 2826 switch (filterMode) 2827 { 2828 case Sampler::NEAREST: 2829 return sampleCubeSeamlessNearestCompare(levels[0], sampler, ref, s, t, faceDepth); 2830 2831 case Sampler::LINEAR: 2832 { 2833 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST]; 2834 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 2835 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i); 2836 2837 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t); 2838 } 2839 2840 case Sampler::NEAREST_MIPMAP_NEAREST: 2841 case Sampler::LINEAR_MIPMAP_NEAREST: 2842 { 2843 int maxLevel = (int)numLevels-1; 2844 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel); 2845 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST; 2846 2847 if (levelFilter == Sampler::NEAREST) 2848 return sampleCubeSeamlessNearestCompare(levels[level], sampler, ref, s, t, faceDepth); 2849 else 2850 { 2851 DE_ASSERT(levelFilter == Sampler::LINEAR); 2852 2853 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST]; 2854 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 2855 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i); 2856 2857 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t); 2858 } 2859 } 2860 2861 case Sampler::NEAREST_MIPMAP_LINEAR: 2862 case Sampler::LINEAR_MIPMAP_LINEAR: 2863 { 2864 int maxLevel = (int)numLevels-1; 2865 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel); 2866 int level1 = de::min(maxLevel, level0 + 1); 2867 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST; 2868 float f = deFloatFrac(lod); 2869 float t0; 2870 float t1; 2871 2872 if (levelFilter == Sampler::NEAREST) 2873 { 2874 t0 = sampleCubeSeamlessNearestCompare(levels[level0], sampler, ref, s, t, faceDepth); 2875 t1 = sampleCubeSeamlessNearestCompare(levels[level1], sampler, ref, s, t, faceDepth); 2876 } 2877 else 2878 { 2879 DE_ASSERT(levelFilter == Sampler::LINEAR); 2880 2881 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST]; 2882 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST]; 2883 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 2884 { 2885 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i); 2886 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i); 2887 } 2888 2889 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t); 2890 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t); 2891 } 2892 2893 return t0*(1.0f - f) + t1*f; 2894 } 2895 2896 default: 2897 DE_ASSERT(DE_FALSE); 2898 return 0.0f; 2899 } 2900} 2901 2902inline int computeMipPyramidLevels (int size) 2903{ 2904 return deLog2Floor32(size)+1; 2905} 2906 2907inline int computeMipPyramidLevels (int width, int height) 2908{ 2909 return deLog2Floor32(de::max(width, height))+1; 2910} 2911 2912inline int computeMipPyramidLevels (int width, int height, int depth) 2913{ 2914 return deLog2Floor32(de::max(width, de::max(height, depth)))+1; 2915} 2916 2917inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx) 2918{ 2919 return de::max(baseLevelSize >> levelNdx, 1); 2920} 2921 2922// TextureLevelPyramid 2923 2924TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels) 2925 : m_format (format) 2926 , m_data (numLevels) 2927 , m_access (numLevels) 2928{ 2929} 2930 2931TextureLevelPyramid::TextureLevelPyramid (const TextureLevelPyramid& other) 2932 : m_format (other.m_format) 2933 , m_data (other.getNumLevels()) 2934 , m_access (other.getNumLevels()) 2935{ 2936 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++) 2937 { 2938 if (!other.isLevelEmpty(levelNdx)) 2939 { 2940 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx); 2941 2942 m_data[levelNdx] = other.m_data[levelNdx]; 2943 m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr()); 2944 } 2945 } 2946} 2947 2948TextureLevelPyramid& TextureLevelPyramid::operator= (const TextureLevelPyramid& other) 2949{ 2950 if (this == &other) 2951 return *this; 2952 2953 m_format = other.m_format; 2954 m_data.resize(other.getNumLevels()); 2955 m_access.resize(other.getNumLevels()); 2956 2957 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++) 2958 { 2959 if (!other.isLevelEmpty(levelNdx)) 2960 { 2961 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx); 2962 2963 m_data[levelNdx] = other.m_data[levelNdx]; 2964 m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr()); 2965 } 2966 else if (!isLevelEmpty(levelNdx)) 2967 clearLevel(levelNdx); 2968 } 2969 2970 return *this; 2971} 2972 2973TextureLevelPyramid::~TextureLevelPyramid (void) 2974{ 2975} 2976 2977void TextureLevelPyramid::allocLevel (int levelNdx, int width, int height, int depth) 2978{ 2979 const int size = m_format.getPixelSize()*width*height*depth; 2980 2981 DE_ASSERT(isLevelEmpty(levelNdx)); 2982 2983 m_data[levelNdx].setStorage(size); 2984 m_access[levelNdx] = PixelBufferAccess(m_format, width, height, depth, m_data[levelNdx].getPtr()); 2985} 2986 2987void TextureLevelPyramid::clearLevel (int levelNdx) 2988{ 2989 DE_ASSERT(!isLevelEmpty(levelNdx)); 2990 2991 m_data[levelNdx].clear(); 2992 m_access[levelNdx] = PixelBufferAccess(); 2993} 2994 2995// Texture1D 2996 2997Texture1D::Texture1D (const TextureFormat& format, int width) 2998 : TextureLevelPyramid (format, computeMipPyramidLevels(width)) 2999 , m_width (width) 3000 , m_view (getNumLevels(), getLevels()) 3001{ 3002} 3003 3004Texture1D::Texture1D (const Texture1D& other) 3005 : TextureLevelPyramid (other) 3006 , m_width (other.m_width) 3007 , m_view (getNumLevels(), getLevels()) 3008{ 3009} 3010 3011Texture1D& Texture1D::operator= (const Texture1D& other) 3012{ 3013 if (this == &other) 3014 return *this; 3015 3016 TextureLevelPyramid::operator=(other); 3017 3018 m_width = other.m_width; 3019 m_view = Texture1DView(getNumLevels(), getLevels()); 3020 3021 return *this; 3022} 3023 3024Texture1D::~Texture1D (void) 3025{ 3026} 3027 3028void Texture1D::allocLevel (int levelNdx) 3029{ 3030 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels())); 3031 3032 const int width = getMipPyramidLevelSize(m_width, levelNdx); 3033 3034 TextureLevelPyramid::allocLevel(levelNdx, width, 1, 1); 3035} 3036 3037// Texture2D 3038 3039Texture2D::Texture2D (const TextureFormat& format, int width, int height) 3040 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height)) 3041 , m_width (width) 3042 , m_height (height) 3043 , m_view (getNumLevels(), getLevels()) 3044{ 3045} 3046 3047Texture2D::Texture2D (const Texture2D& other) 3048 : TextureLevelPyramid (other) 3049 , m_width (other.m_width) 3050 , m_height (other.m_height) 3051 , m_view (getNumLevels(), getLevels()) 3052{ 3053} 3054 3055Texture2D& Texture2D::operator= (const Texture2D& other) 3056{ 3057 if (this == &other) 3058 return *this; 3059 3060 TextureLevelPyramid::operator=(other); 3061 3062 m_width = other.m_width; 3063 m_height = other.m_height; 3064 m_view = Texture2DView(getNumLevels(), getLevels()); 3065 3066 return *this; 3067} 3068 3069Texture2D::~Texture2D (void) 3070{ 3071} 3072 3073void Texture2D::allocLevel (int levelNdx) 3074{ 3075 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels())); 3076 3077 const int width = getMipPyramidLevelSize(m_width, levelNdx); 3078 const int height = getMipPyramidLevelSize(m_height, levelNdx); 3079 3080 TextureLevelPyramid::allocLevel(levelNdx, width, height, 1); 3081} 3082 3083// TextureCubeView 3084 3085TextureCubeView::TextureCubeView (void) 3086 : m_numLevels(0) 3087{ 3088 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++) 3089 m_levels[ndx] = DE_NULL; 3090} 3091 3092TextureCubeView::TextureCubeView (int numLevels, const ConstPixelBufferAccess* const (&levels) [CUBEFACE_LAST]) 3093 : m_numLevels(numLevels) 3094{ 3095 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++) 3096 m_levels[ndx] = levels[ndx]; 3097} 3098 3099tcu::Vec4 TextureCubeView::sample (const Sampler& sampler, float s, float t, float r, float lod) const 3100{ 3101 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE); 3102 3103 // Computes (face, s, t). 3104 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r)); 3105 if (sampler.seamlessCubeMap) 3106 return sampleLevelArrayCubeSeamless(m_levels, m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod); 3107 else 3108 return sampleLevelArray2D(m_levels[coords.face], m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod); 3109} 3110 3111float TextureCubeView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const 3112{ 3113 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE); 3114 3115 // Computes (face, s, t). 3116 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r)); 3117 if (sampler.seamlessCubeMap) 3118 return sampleLevelArrayCubeSeamlessCompare(m_levels, m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod); 3119 else 3120 return sampleLevelArray2DCompare(m_levels[coords.face], m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, 0)); 3121} 3122 3123Vec4 TextureCubeView::gather (const Sampler& sampler, float s, float t, float r, int componentNdx) const 3124{ 3125 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE); 3126 3127 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST]; 3128 for (int i = 0; i < (int)CUBEFACE_LAST; i++) 3129 faceAccesses[i] = m_levels[i][0]; 3130 3131 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r)); 3132 const int size = faceAccesses[0].getWidth(); 3133 // Non-normalized coordinates. 3134 float u = coords.s; 3135 float v = coords.t; 3136 3137 if (sampler.normalizedCoords) 3138 { 3139 u = unnormalize(sampler.wrapS, coords.s, size); 3140 v = unnormalize(sampler.wrapT, coords.t, size); 3141 } 3142 3143 Vec4 sampleColors[4]; 3144 getCubeLinearSamples(faceAccesses, coords.face, u, v, 0, sampleColors); 3145 3146 const int sampleIndices[4] = { 2, 3, 1, 0 }; // \note Gather returns the samples in a non-obvious order. 3147 Vec4 result; 3148 for (int i = 0; i < 4; i++) 3149 result[i] = sampleColors[sampleIndices[i]][componentNdx]; 3150 3151 return result; 3152} 3153 3154Vec4 TextureCubeView::gatherCompare (const Sampler& sampler, float ref, float s, float t, float r) const 3155{ 3156 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE); 3157 DE_ASSERT(m_levels[0][0].getFormat().order == TextureFormat::D || m_levels[0][0].getFormat().order == TextureFormat::DS); 3158 DE_ASSERT(sampler.compareChannel == 0); 3159 3160 Sampler noCompareSampler = sampler; 3161 noCompareSampler.compare = Sampler::COMPAREMODE_NONE; 3162 3163 const Vec4 gathered = gather(noCompareSampler, s, t, r, 0 /* component 0: depth */); 3164 const bool isFixedPoint = isFixedPointDepthTextureFormat(m_levels[0][0].getFormat()); 3165 Vec4 result; 3166 for (int i = 0; i < 4; i++) 3167 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint); 3168 3169 return result; 3170} 3171 3172// TextureCube 3173 3174TextureCube::TextureCube (const TextureFormat& format, int size) 3175 : m_format (format) 3176 , m_size (size) 3177{ 3178 const int numLevels = computeMipPyramidLevels(m_size); 3179 const ConstPixelBufferAccess* levels[CUBEFACE_LAST]; 3180 3181 for (int face = 0; face < CUBEFACE_LAST; face++) 3182 { 3183 m_data[face].resize(numLevels); 3184 m_access[face].resize(numLevels); 3185 levels[face] = &m_access[face][0]; 3186 } 3187 3188 m_view = TextureCubeView(numLevels, levels); 3189} 3190 3191TextureCube::TextureCube (const TextureCube& other) 3192 : m_format (other.m_format) 3193 , m_size (other.m_size) 3194{ 3195 const int numLevels = computeMipPyramidLevels(m_size); 3196 const ConstPixelBufferAccess* levels[CUBEFACE_LAST]; 3197 3198 for (int face = 0; face < CUBEFACE_LAST; face++) 3199 { 3200 m_data[face].resize(numLevels); 3201 m_access[face].resize(numLevels); 3202 levels[face] = &m_access[face][0]; 3203 } 3204 3205 m_view = TextureCubeView(numLevels, levels); 3206 3207 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 3208 { 3209 for (int face = 0; face < CUBEFACE_LAST; face++) 3210 { 3211 if (!other.isLevelEmpty((CubeFace)face, levelNdx)) 3212 { 3213 allocLevel((CubeFace)face, levelNdx); 3214 copy(getLevelFace(levelNdx, (CubeFace)face), 3215 other.getLevelFace(levelNdx, (CubeFace)face)); 3216 } 3217 } 3218 } 3219} 3220 3221TextureCube& TextureCube::operator= (const TextureCube& other) 3222{ 3223 if (this == &other) 3224 return *this; 3225 3226 const int numLevels = computeMipPyramidLevels(other.m_size); 3227 const ConstPixelBufferAccess* levels[CUBEFACE_LAST]; 3228 3229 for (int face = 0; face < CUBEFACE_LAST; face++) 3230 { 3231 m_data[face].resize(numLevels); 3232 m_access[face].resize(numLevels); 3233 levels[face] = &m_access[face][0]; 3234 } 3235 3236 m_format = other.m_format; 3237 m_size = other.m_size; 3238 m_view = TextureCubeView(numLevels, levels); 3239 3240 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 3241 { 3242 for (int face = 0; face < CUBEFACE_LAST; face++) 3243 { 3244 if (!isLevelEmpty((CubeFace)face, levelNdx)) 3245 clearLevel((CubeFace)face, levelNdx); 3246 3247 if (!other.isLevelEmpty((CubeFace)face, levelNdx)) 3248 { 3249 allocLevel((CubeFace)face, levelNdx); 3250 copy(getLevelFace(levelNdx, (CubeFace)face), 3251 other.getLevelFace(levelNdx, (CubeFace)face)); 3252 } 3253 } 3254 } 3255 3256 return *this; 3257} 3258 3259TextureCube::~TextureCube (void) 3260{ 3261} 3262 3263void TextureCube::allocLevel (tcu::CubeFace face, int levelNdx) 3264{ 3265 const int size = getMipPyramidLevelSize(m_size, levelNdx); 3266 const int dataSize = m_format.getPixelSize()*size*size; 3267 DE_ASSERT(isLevelEmpty(face, levelNdx)); 3268 3269 m_data[face][levelNdx].setStorage(dataSize); 3270 m_access[face][levelNdx] = PixelBufferAccess(m_format, size, size, 1, m_data[face][levelNdx].getPtr()); 3271} 3272 3273void TextureCube::clearLevel (tcu::CubeFace face, int levelNdx) 3274{ 3275 DE_ASSERT(!isLevelEmpty(face, levelNdx)); 3276 m_data[face][levelNdx].clear(); 3277 m_access[face][levelNdx] = PixelBufferAccess(); 3278} 3279 3280// Texture1DArrayView 3281 3282Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels) 3283 : m_numLevels (numLevels) 3284 , m_levels (levels) 3285{ 3286} 3287 3288inline int Texture1DArrayView::selectLayer (float r) const 3289{ 3290 DE_ASSERT(m_numLevels > 0 && m_levels); 3291 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getHeight()-1); 3292} 3293 3294Vec4 Texture1DArrayView::sample (const Sampler& sampler, float s, float t, float lod) const 3295{ 3296 return sampleLevelArray1D(m_levels, m_numLevels, sampler, s, selectLayer(t), lod); 3297} 3298 3299Vec4 Texture1DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float lod, deInt32 offset) const 3300{ 3301 return sampleLevelArray1DOffset(m_levels, m_numLevels, sampler, s, lod, IVec2(offset, selectLayer(t))); 3302} 3303 3304float Texture1DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float lod) const 3305{ 3306 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(0, selectLayer(t))); 3307} 3308 3309float Texture1DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float lod, deInt32 offset) const 3310{ 3311 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(offset, selectLayer(t))); 3312} 3313 3314// Texture2DArrayView 3315 3316Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels) 3317 : m_numLevels (numLevels) 3318 , m_levels (levels) 3319{ 3320} 3321 3322inline int Texture2DArrayView::selectLayer (float r) const 3323{ 3324 DE_ASSERT(m_numLevels > 0 && m_levels); 3325 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getDepth()-1); 3326} 3327 3328Vec4 Texture2DArrayView::sample (const Sampler& sampler, float s, float t, float r, float lod) const 3329{ 3330 return sampleLevelArray2D(m_levels, m_numLevels, sampler, s, t, selectLayer(r), lod); 3331} 3332 3333float Texture2DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const 3334{ 3335 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(0, 0, selectLayer(r))); 3336} 3337 3338Vec4 Texture2DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float r, float lod, const IVec2& offset) const 3339{ 3340 return sampleLevelArray2DOffset(m_levels, m_numLevels, sampler, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r))); 3341} 3342 3343float Texture2DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float r, float lod, const IVec2& offset) const 3344{ 3345 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r))); 3346} 3347 3348Vec4 Texture2DArrayView::gatherOffsets (const Sampler& sampler, float s, float t, float r, int componentNdx, const IVec2 (&offsets)[4]) const 3349{ 3350 return gatherArray2DOffsets(m_levels[0], sampler, s, t, selectLayer(r), componentNdx, offsets); 3351} 3352 3353Vec4 Texture2DArrayView::gatherOffsetsCompare (const Sampler& sampler, float ref, float s, float t, float r, const IVec2 (&offsets)[4]) const 3354{ 3355 return gatherArray2DOffsetsCompare(m_levels[0], sampler, ref, s, t, selectLayer(r), offsets); 3356} 3357 3358// Texture1DArray 3359 3360Texture1DArray::Texture1DArray (const TextureFormat& format, int width, int numLayers) 3361 : TextureLevelPyramid (format, computeMipPyramidLevels(width)) 3362 , m_width (width) 3363 , m_numLayers (numLayers) 3364 , m_view (getNumLevels(), getLevels()) 3365{ 3366} 3367 3368Texture1DArray::Texture1DArray (const Texture1DArray& other) 3369 : TextureLevelPyramid (other) 3370 , m_width (other.m_width) 3371 , m_numLayers (other.m_numLayers) 3372 , m_view (getNumLevels(), getLevels()) 3373{ 3374} 3375 3376Texture1DArray& Texture1DArray::operator= (const Texture1DArray& other) 3377{ 3378 if (this == &other) 3379 return *this; 3380 3381 TextureLevelPyramid::operator=(other); 3382 3383 m_width = other.m_width; 3384 m_numLayers = other.m_numLayers; 3385 m_view = Texture1DArrayView(getNumLevels(), getLevels()); 3386 3387 return *this; 3388} 3389 3390Texture1DArray::~Texture1DArray (void) 3391{ 3392} 3393 3394void Texture1DArray::allocLevel (int levelNdx) 3395{ 3396 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels())); 3397 3398 const int width = getMipPyramidLevelSize(m_width, levelNdx); 3399 3400 TextureLevelPyramid::allocLevel(levelNdx, width, m_numLayers, 1); 3401} 3402 3403// Texture2DArray 3404 3405Texture2DArray::Texture2DArray (const TextureFormat& format, int width, int height, int numLayers) 3406 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height)) 3407 , m_width (width) 3408 , m_height (height) 3409 , m_numLayers (numLayers) 3410 , m_view (getNumLevels(), getLevels()) 3411{ 3412} 3413 3414Texture2DArray::Texture2DArray (const Texture2DArray& other) 3415 : TextureLevelPyramid (other) 3416 , m_width (other.m_width) 3417 , m_height (other.m_height) 3418 , m_numLayers (other.m_numLayers) 3419 , m_view (getNumLevels(), getLevels()) 3420{ 3421} 3422 3423Texture2DArray& Texture2DArray::operator= (const Texture2DArray& other) 3424{ 3425 if (this == &other) 3426 return *this; 3427 3428 TextureLevelPyramid::operator=(other); 3429 3430 m_width = other.m_width; 3431 m_height = other.m_height; 3432 m_numLayers = other.m_numLayers; 3433 m_view = Texture2DArrayView(getNumLevels(), getLevels()); 3434 3435 return *this; 3436} 3437 3438Texture2DArray::~Texture2DArray (void) 3439{ 3440} 3441 3442void Texture2DArray::allocLevel (int levelNdx) 3443{ 3444 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels())); 3445 3446 const int width = getMipPyramidLevelSize(m_width, levelNdx); 3447 const int height = getMipPyramidLevelSize(m_height, levelNdx); 3448 3449 TextureLevelPyramid::allocLevel(levelNdx, width, height, m_numLayers); 3450} 3451 3452// Texture3DView 3453 3454Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels) 3455 : m_numLevels (numLevels) 3456 , m_levels (levels) 3457{ 3458} 3459 3460// Texture3D 3461 3462Texture3D::Texture3D (const TextureFormat& format, int width, int height, int depth) 3463 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height, depth)) 3464 , m_width (width) 3465 , m_height (height) 3466 , m_depth (depth) 3467 , m_view (getNumLevels(), getLevels()) 3468{ 3469} 3470 3471Texture3D::Texture3D (const Texture3D& other) 3472 : TextureLevelPyramid (other) 3473 , m_width (other.m_width) 3474 , m_height (other.m_height) 3475 , m_depth (other.m_depth) 3476 , m_view (getNumLevels(), getLevels()) 3477{ 3478} 3479 3480Texture3D& Texture3D::operator= (const Texture3D& other) 3481{ 3482 if (this == &other) 3483 return *this; 3484 3485 TextureLevelPyramid::operator=(other); 3486 3487 m_width = other.m_width; 3488 m_height = other.m_height; 3489 m_depth = other.m_depth; 3490 m_view = Texture3DView(getNumLevels(), getLevels()); 3491 3492 return *this; 3493} 3494 3495Texture3D::~Texture3D (void) 3496{ 3497} 3498 3499void Texture3D::allocLevel (int levelNdx) 3500{ 3501 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels())); 3502 3503 const int width = getMipPyramidLevelSize(m_width, levelNdx); 3504 const int height = getMipPyramidLevelSize(m_height, levelNdx); 3505 const int depth = getMipPyramidLevelSize(m_depth, levelNdx); 3506 3507 TextureLevelPyramid::allocLevel(levelNdx, width, height, depth); 3508} 3509 3510// TextureCubeArrayView 3511 3512TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels) 3513 : m_numLevels (numLevels) 3514 , m_levels (levels) 3515{ 3516} 3517 3518inline int TextureCubeArrayView::selectSlice (float q) const 3519{ 3520 DE_ASSERT(m_numLevels > 0 && m_levels); 3521 DE_ASSERT((m_levels[0].getDepth() % 6) == 0); 3522 3523 return de::clamp(deFloorFloatToInt32(q + 0.5f), 0, (m_levels[0].getDepth() / 6)-1); 3524} 3525 3526tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const 3527{ 3528 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r)); 3529 const int slice = selectSlice(q); 3530 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(coords.face); 3531 3532 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE); 3533 3534 if (sampler.seamlessCubeMap) 3535 return sampleCubeArraySeamless(m_levels, m_numLevels, slice, coords.face, sampler, coords.s, coords.t, lod); 3536 else 3537 return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod); 3538} 3539 3540float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const 3541{ 3542 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r)); 3543 const int slice = selectSlice(q); 3544 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(coords.face); 3545 3546 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE); 3547 3548 if (sampler.seamlessCubeMap) 3549 return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, slice, coords.face, sampler, ref, coords.s, coords.t, lod); 3550 else 3551 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth)); 3552} 3553 3554// TextureCubeArray 3555 3556TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int numLayers) 3557 : TextureLevelPyramid (format, computeMipPyramidLevels(size)) 3558 , m_size (size) 3559 , m_numLayers (numLayers) 3560 , m_view (getNumLevels(), getLevels()) 3561{ 3562 DE_ASSERT(m_numLayers % 6 == 0); 3563} 3564 3565TextureCubeArray::TextureCubeArray (const TextureCubeArray& other) 3566 : TextureLevelPyramid (other) 3567 , m_size (other.m_size) 3568 , m_numLayers (other.m_numLayers) 3569 , m_view (getNumLevels(), getLevels()) 3570{ 3571 DE_ASSERT(m_numLayers % 6 == 0); 3572} 3573 3574TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other) 3575{ 3576 if (this == &other) 3577 return *this; 3578 3579 TextureLevelPyramid::operator=(other); 3580 3581 m_size = other.m_size; 3582 m_numLayers = other.m_numLayers; 3583 m_view = TextureCubeArrayView(getNumLevels(), getLevels()); 3584 3585 DE_ASSERT(m_numLayers % 6 == 0); 3586 3587 return *this; 3588} 3589 3590TextureCubeArray::~TextureCubeArray (void) 3591{ 3592} 3593 3594void TextureCubeArray::allocLevel (int levelNdx) 3595{ 3596 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels())); 3597 3598 const int size = getMipPyramidLevelSize(m_size, levelNdx); 3599 3600 TextureLevelPyramid::allocLevel(levelNdx, size, size, m_numLayers); 3601} 3602 3603std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order) 3604{ 3605 switch (order) 3606 { 3607 case TextureFormat::R: return str << "R"; 3608 case TextureFormat::A: return str << "A"; 3609 case TextureFormat::I: return str << "I"; 3610 case TextureFormat::L: return str << "L"; 3611 case TextureFormat::LA: return str << "LA"; 3612 case TextureFormat::RG: return str << "RG"; 3613 case TextureFormat::RA: return str << "RA"; 3614 case TextureFormat::RGB: return str << "RGB"; 3615 case TextureFormat::RGBA: return str << "RGBA"; 3616 case TextureFormat::ARGB: return str << "ARGB"; 3617 case TextureFormat::BGRA: return str << "BGRA"; 3618 case TextureFormat::CHANNELORDER_LAST: return str << "CHANNELORDER_LAST"; 3619 default: return str << "UNKNOWN(" << (int)order << ")"; 3620 } 3621} 3622 3623std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelType type) 3624{ 3625 switch (type) 3626 { 3627 case TextureFormat::SNORM_INT8: return str << "SNORM_INT8"; 3628 case TextureFormat::SNORM_INT16: return str << "SNORM_INT16"; 3629 case TextureFormat::UNORM_INT8: return str << "UNORM_INT8"; 3630 case TextureFormat::UNORM_INT16: return str << "UNORM_INT16"; 3631 case TextureFormat::UNORM_SHORT_565: return str << "UNORM_SHORT_565"; 3632 case TextureFormat::UNORM_SHORT_555: return str << "UNORM_SHORT_555"; 3633 case TextureFormat::UNORM_SHORT_4444: return str << "UNORM_SHORT_4444"; 3634 case TextureFormat::UNORM_SHORT_5551: return str << "UNORM_SHORT_5551"; 3635 case TextureFormat::UNORM_INT_101010: return str << "UNORM_INT_101010"; 3636 case TextureFormat::SIGNED_INT8: return str << "SIGNED_INT8"; 3637 case TextureFormat::SIGNED_INT16: return str << "SIGNED_INT16"; 3638 case TextureFormat::SIGNED_INT32: return str << "SIGNED_INT32"; 3639 case TextureFormat::UNSIGNED_INT8: return str << "UNSIGNED_INT8"; 3640 case TextureFormat::UNSIGNED_INT16: return str << "UNSIGNED_INT16"; 3641 case TextureFormat::UNSIGNED_INT32: return str << "UNSIGNED_INT32"; 3642 case TextureFormat::HALF_FLOAT: return str << "HALF_FLOAT"; 3643 case TextureFormat::FLOAT: return str << "FLOAT"; 3644 case TextureFormat::CHANNELTYPE_LAST: return str << "CHANNELTYPE_LAST"; 3645 default: return str << "UNKNOWN(" << (int)type << ")"; 3646 } 3647} 3648 3649std::ostream& operator<< (std::ostream& str, CubeFace face) 3650{ 3651 switch (face) 3652 { 3653 case CUBEFACE_NEGATIVE_X: return str << "CUBEFACE_NEGATIVE_X"; 3654 case CUBEFACE_POSITIVE_X: return str << "CUBEFACE_POSITIVE_X"; 3655 case CUBEFACE_NEGATIVE_Y: return str << "CUBEFACE_NEGATIVE_Y"; 3656 case CUBEFACE_POSITIVE_Y: return str << "CUBEFACE_POSITIVE_Y"; 3657 case CUBEFACE_NEGATIVE_Z: return str << "CUBEFACE_NEGATIVE_Z"; 3658 case CUBEFACE_POSITIVE_Z: return str << "CUBEFACE_POSITIVE_Z"; 3659 case CUBEFACE_LAST: return str << "CUBEFACE_LAST"; 3660 default: return str << "UNKNOWN(" << (int)face << ")"; 3661 } 3662} 3663 3664std::ostream& operator<< (std::ostream& str, TextureFormat format) 3665{ 3666 return str << format.order << ", " << format.type << ""; 3667} 3668 3669std::ostream& operator<< (std::ostream& str, const ConstPixelBufferAccess& access) 3670{ 3671 return str << "format = (" << access.getFormat() << "), size = " 3672 << access.getWidth() << " x " << access.getHeight() << " x " << access.getDepth() 3673 << ", pitch = " << access.getRowPitch() << " / " << access.getSlicePitch(); 3674} 3675 3676} // tcu 3677