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