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