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 Texture utilities. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "tcuTextureUtil.hpp" 25 #include "tcuVectorUtil.hpp" 26 #include "deRandom.hpp" 27 #include "deMath.h" 28 #include "deMemory.h" 29 30 #include <limits> 31 32 namespace tcu 33 { 34 35 static inline float sRGBChannelToLinear (float cs) 36 { 37 if (cs <= 0.04045) 38 return cs / 12.92f; 39 else 40 return deFloatPow((cs + 0.055f) / 1.055f, 2.4f); 41 } 42 43 static inline float linearChannelToSRGB (float cl) 44 { 45 if (cl <= 0.0f) 46 return 0.0f; 47 else if (cl < 0.0031308f) 48 return 12.92f*cl; 49 else if (cl < 1.0f) 50 return 1.055f*deFloatPow(cl, 0.41666f) - 0.055f; 51 else 52 return 1.0f; 53 } 54 55 //! Convert sRGB to linear colorspace 56 Vec4 sRGBToLinear (const Vec4& cs) 57 { 58 return Vec4(sRGBChannelToLinear(cs[0]), 59 sRGBChannelToLinear(cs[1]), 60 sRGBChannelToLinear(cs[2]), 61 cs[3]); 62 } 63 64 //! Convert from linear to sRGB colorspace 65 Vec4 linearToSRGB (const Vec4& cl) 66 { 67 return Vec4(linearChannelToSRGB(cl[0]), 68 linearChannelToSRGB(cl[1]), 69 linearChannelToSRGB(cl[2]), 70 cl[3]); 71 } 72 73 bool isSRGB (TextureFormat format) 74 { 75 return format.order == TextureFormat::sR || 76 format.order == TextureFormat::sRG || 77 format.order == TextureFormat::sRGB || 78 format.order == TextureFormat::sRGBA; 79 } 80 81 bool isCombinedDepthStencilType (TextureFormat::ChannelType type) 82 { 83 // make sure to update this if type table is updated 84 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27); 85 86 return type == TextureFormat::UNSIGNED_INT_24_8 || 87 type == TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV; 88 } 89 90 //! Get texture channel class for format 91 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType) 92 { 93 // make sure this table is updated if format table is updated 94 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27); 95 96 switch (channelType) 97 { 98 case TextureFormat::SNORM_INT8: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT; 99 case TextureFormat::SNORM_INT16: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT; 100 case TextureFormat::SNORM_INT32: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT; 101 case TextureFormat::UNORM_INT8: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 102 case TextureFormat::UNORM_INT16: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 103 case TextureFormat::UNORM_INT24: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 104 case TextureFormat::UNORM_INT32: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 105 case TextureFormat::UNORM_SHORT_565: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 106 case TextureFormat::UNORM_SHORT_555: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 107 case TextureFormat::UNORM_SHORT_4444: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 108 case TextureFormat::UNORM_SHORT_5551: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 109 case TextureFormat::UNORM_INT_101010: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 110 case TextureFormat::UNORM_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 111 case TextureFormat::UNSIGNED_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 112 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return TEXTURECHANNELCLASS_FLOATING_POINT; 113 case TextureFormat::UNSIGNED_INT_999_E5_REV: return TEXTURECHANNELCLASS_FLOATING_POINT; 114 case TextureFormat::UNSIGNED_INT_24_8: return TEXTURECHANNELCLASS_LAST; //!< packed unorm24-uint8 115 case TextureFormat::SIGNED_INT8: return TEXTURECHANNELCLASS_SIGNED_INTEGER; 116 case TextureFormat::SIGNED_INT16: return TEXTURECHANNELCLASS_SIGNED_INTEGER; 117 case TextureFormat::SIGNED_INT32: return TEXTURECHANNELCLASS_SIGNED_INTEGER; 118 case TextureFormat::UNSIGNED_INT8: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 119 case TextureFormat::UNSIGNED_INT16: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 120 case TextureFormat::UNSIGNED_INT24: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 121 case TextureFormat::UNSIGNED_INT32: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 122 case TextureFormat::HALF_FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT; 123 case TextureFormat::FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT; 124 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return TEXTURECHANNELCLASS_LAST; //!< packed float32-pad24-uint8 125 default: return TEXTURECHANNELCLASS_LAST; 126 } 127 } 128 129 /*--------------------------------------------------------------------*//*! 130 * \brief Get access to subregion of pixel buffer 131 * \param access Parent access object 132 * \param x X offset 133 * \param y Y offset 134 * \param z Z offset 135 * \param width Width 136 * \param height Height 137 * \param depth Depth 138 * \return Access object that targets given subregion of parent access object 139 *//*--------------------------------------------------------------------*/ 140 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth) 141 { 142 DE_ASSERT(de::inBounds(x, 0, access.getWidth())); 143 DE_ASSERT(de::inRange(x+width, x+1, access.getWidth())); 144 145 DE_ASSERT(de::inBounds(y, 0, access.getHeight())); 146 DE_ASSERT(de::inRange(y+height, y+1, access.getHeight())); 147 148 DE_ASSERT(de::inBounds(z, 0, access.getDepth())); 149 DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth())); 150 151 return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(), 152 (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z); 153 } 154 155 /*--------------------------------------------------------------------*//*! 156 * \brief Get access to subregion of pixel buffer 157 * \param access Parent access object 158 * \param x X offset 159 * \param y Y offset 160 * \param z Z offset 161 * \param width Width 162 * \param height Height 163 * \param depth Depth 164 * \return Access object that targets given subregion of parent access object 165 *//*--------------------------------------------------------------------*/ 166 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth) 167 { 168 DE_ASSERT(de::inBounds(x, 0, access.getWidth())); 169 DE_ASSERT(de::inRange(x+width, x+1, access.getWidth())); 170 171 DE_ASSERT(de::inBounds(y, 0, access.getHeight())); 172 DE_ASSERT(de::inRange(y+height, y+1, access.getHeight())); 173 174 DE_ASSERT(de::inBounds(z, 0, access.getDepth())); 175 DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth())); 176 177 return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(), 178 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z); 179 } 180 181 /*--------------------------------------------------------------------*//*! 182 * \brief Get access to subregion of pixel buffer 183 * \param access Parent access object 184 * \param x X offset 185 * \param y Y offset 186 * \param width Width 187 * \param height Height 188 * \return Access object that targets given subregion of parent access object 189 *//*--------------------------------------------------------------------*/ 190 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height) 191 { 192 return getSubregion(access, x, y, 0, width, height, 1); 193 } 194 195 /*--------------------------------------------------------------------*//*! 196 * \brief Get access to subregion of pixel buffer 197 * \param access Parent access object 198 * \param x X offset 199 * \param y Y offset 200 * \param width Width 201 * \param height Height 202 * \return Access object that targets given subregion of parent access object 203 *//*--------------------------------------------------------------------*/ 204 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height) 205 { 206 return getSubregion(access, x, y, 0, width, height, 1); 207 } 208 209 /*--------------------------------------------------------------------*//*! 210 * \brief Flip rows in Y direction 211 * \param access Access object 212 * \return Modified access object where Y coordinates are reversed 213 *//*--------------------------------------------------------------------*/ 214 PixelBufferAccess flipYAccess (const PixelBufferAccess& access) 215 { 216 const int rowPitch = access.getRowPitch(); 217 const int offsetToLast = rowPitch*(access.getHeight()-1); 218 const tcu::IVec3 pitch (access.getPixelPitch(), -rowPitch, access.getSlicePitch()); 219 220 return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast); 221 } 222 223 /*--------------------------------------------------------------------*//*! 224 * \brief Flip rows in Y direction 225 * \param access Access object 226 * \return Modified access object where Y coordinates are reversed 227 *//*--------------------------------------------------------------------*/ 228 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access) 229 { 230 const int rowPitch = access.getRowPitch(); 231 const int offsetToLast = rowPitch*(access.getHeight()-1); 232 const tcu::IVec3 pitch (access.getPixelPitch(), -rowPitch, access.getSlicePitch()); 233 234 return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast); 235 } 236 237 static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType) 238 { 239 // make sure this table is updated if format table is updated 240 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27); 241 242 float cMin = 0.0f; 243 float cMax = 0.0f; 244 245 switch (channelType) 246 { 247 // Signed normalized formats. 248 case TextureFormat::SNORM_INT8: 249 case TextureFormat::SNORM_INT16: 250 case TextureFormat::SNORM_INT32: cMin = -1.0f; cMax = 1.0f; break; 251 252 // Unsigned normalized formats. 253 case TextureFormat::UNORM_INT8: 254 case TextureFormat::UNORM_INT16: 255 case TextureFormat::UNORM_INT24: 256 case TextureFormat::UNORM_INT32: 257 case TextureFormat::UNORM_SHORT_565: 258 case TextureFormat::UNORM_SHORT_4444: 259 case TextureFormat::UNORM_INT_101010: 260 case TextureFormat::UNORM_INT_1010102_REV: cMin = 0.0f; cMax = 1.0f; break; 261 262 // Misc formats. 263 case TextureFormat::SIGNED_INT8: cMin = -128.0f; cMax = 127.0f; break; 264 case TextureFormat::SIGNED_INT16: cMin = -32768.0f; cMax = 32767.0f; break; 265 case TextureFormat::SIGNED_INT32: cMin = -2147483648.0f; cMax = 2147483647.0f; break; 266 case TextureFormat::UNSIGNED_INT8: cMin = 0.0f; cMax = 255.0f; break; 267 case TextureFormat::UNSIGNED_INT16: cMin = 0.0f; cMax = 65535.0f; break; 268 case TextureFormat::UNSIGNED_INT24: cMin = 0.0f; cMax = 16777215.0f; break; 269 case TextureFormat::UNSIGNED_INT32: cMin = 0.0f; cMax = 4294967295.f; break; 270 case TextureFormat::HALF_FLOAT: cMin = -1e3f; cMax = 1e3f; break; 271 case TextureFormat::FLOAT: cMin = -1e5f; cMax = 1e5f; break; 272 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: cMin = 0.0f; cMax = 1e4f; break; 273 case TextureFormat::UNSIGNED_INT_999_E5_REV: cMin = 0.0f; cMax = 1e5f; break; 274 275 default: 276 DE_ASSERT(false); 277 } 278 279 return Vec2(cMin, cMax); 280 } 281 282 /*--------------------------------------------------------------------*//*! 283 * \brief Get standard parameters for testing texture format 284 * 285 * Returns TextureFormatInfo that describes good parameters for exercising 286 * given TextureFormat. Parameters include value ranges per channel and 287 * suitable lookup scaling and bias in order to reduce result back to 288 * 0..1 range. 289 *//*--------------------------------------------------------------------*/ 290 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format) 291 { 292 // Special cases. 293 if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV)) 294 return TextureFormatInfo(Vec4( 0.0f, 0.0f, 0.0f, 0.0f), 295 Vec4( 1023.0f, 1023.0f, 1023.0f, 3.0f), 296 Vec4(1.0f/1023.f, 1.0f/1023.0f, 1.0f/1023.0f, 1.0f/3.0f), 297 Vec4( 0.0f, 0.0f, 0.0f, 0.0f)); 298 else if (format.order == TextureFormat::D || format.order == TextureFormat::DS) 299 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.0f), 300 Vec4(1.0f, 1.0f, 1.0f, 0.0f), 301 Vec4(1.0f, 1.0f, 1.0f, 1.0f), 302 Vec4(0.0f, 0.0f, 0.0f, 0.0f)); // Depth / stencil formats. 303 else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551)) 304 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f), 305 Vec4(1.0f, 1.0f, 1.0f, 1.5f), 306 Vec4(1.0f, 1.0f, 1.0f, 1.0f), 307 Vec4(0.0f, 0.0f, 0.0f, 0.0f)); 308 309 const Vec2 cRange = getChannelValueRange(format.type); 310 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components; 311 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 312 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 313 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 314 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 315 const float scale = 1.0f / (cRange[1] - cRange[0]); 316 const float bias = -cRange[0] * scale; 317 318 return TextureFormatInfo(select(cRange[0], 0.0f, chnMask), 319 select(cRange[1], 0.0f, chnMask), 320 select(scale, 1.0f, chnMask), 321 select(bias, 0.0f, chnMask)); 322 } 323 324 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType) 325 { 326 // make sure this table is updated if format table is updated 327 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27); 328 329 switch (channelType) 330 { 331 case TextureFormat::SNORM_INT8: return IVec4(8); 332 case TextureFormat::SNORM_INT16: return IVec4(16); 333 case TextureFormat::SNORM_INT32: return IVec4(32); 334 case TextureFormat::UNORM_INT8: return IVec4(8); 335 case TextureFormat::UNORM_INT16: return IVec4(16); 336 case TextureFormat::UNORM_INT24: return IVec4(24); 337 case TextureFormat::UNORM_INT32: return IVec4(32); 338 case TextureFormat::UNORM_SHORT_565: return IVec4(5,6,5,0); 339 case TextureFormat::UNORM_SHORT_4444: return IVec4(4); 340 case TextureFormat::UNORM_SHORT_555: return IVec4(5,5,5,0); 341 case TextureFormat::UNORM_SHORT_5551: return IVec4(5,5,5,1); 342 case TextureFormat::UNORM_INT_101010: return IVec4(10,10,10,0); 343 case TextureFormat::UNORM_INT_1010102_REV: return IVec4(10,10,10,2); 344 case TextureFormat::SIGNED_INT8: return IVec4(8); 345 case TextureFormat::SIGNED_INT16: return IVec4(16); 346 case TextureFormat::SIGNED_INT32: return IVec4(32); 347 case TextureFormat::UNSIGNED_INT8: return IVec4(8); 348 case TextureFormat::UNSIGNED_INT16: return IVec4(16); 349 case TextureFormat::UNSIGNED_INT24: return IVec4(24); 350 case TextureFormat::UNSIGNED_INT32: return IVec4(32); 351 case TextureFormat::UNSIGNED_INT_1010102_REV: return IVec4(10,10,10,2); 352 case TextureFormat::UNSIGNED_INT_24_8: return IVec4(24,8,0,0); 353 case TextureFormat::HALF_FLOAT: return IVec4(16); 354 case TextureFormat::FLOAT: return IVec4(32); 355 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(11,11,10,0); 356 case TextureFormat::UNSIGNED_INT_999_E5_REV: return IVec4(9,9,9,0); 357 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(32,8,0,0); 358 default: 359 DE_ASSERT(false); 360 return IVec4(0); 361 } 362 } 363 364 IVec4 getTextureFormatBitDepth (const TextureFormat& format) 365 { 366 const IVec4 chnBits = getChannelBitDepth(format.type); 367 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components; 368 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 369 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 370 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 371 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 372 const IVec4 chnSwz = IVec4((chnMask[0]) ? ((int)map[0]) : (0), 373 (chnMask[1]) ? ((int)map[1]) : (0), 374 (chnMask[2]) ? ((int)map[2]) : (0), 375 (chnMask[3]) ? ((int)map[3]) : (0)); 376 377 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask); 378 } 379 380 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType) 381 { 382 // make sure this table is updated if format table is updated 383 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27); 384 385 switch (channelType) 386 { 387 case TextureFormat::SNORM_INT8: 388 case TextureFormat::SNORM_INT16: 389 case TextureFormat::SNORM_INT32: 390 case TextureFormat::UNORM_INT8: 391 case TextureFormat::UNORM_INT16: 392 case TextureFormat::UNORM_INT24: 393 case TextureFormat::UNORM_INT32: 394 case TextureFormat::UNORM_SHORT_565: 395 case TextureFormat::UNORM_SHORT_4444: 396 case TextureFormat::UNORM_SHORT_555: 397 case TextureFormat::UNORM_SHORT_5551: 398 case TextureFormat::UNORM_INT_101010: 399 case TextureFormat::UNORM_INT_1010102_REV: 400 case TextureFormat::SIGNED_INT8: 401 case TextureFormat::SIGNED_INT16: 402 case TextureFormat::SIGNED_INT32: 403 case TextureFormat::UNSIGNED_INT8: 404 case TextureFormat::UNSIGNED_INT16: 405 case TextureFormat::UNSIGNED_INT24: 406 case TextureFormat::UNSIGNED_INT32: 407 case TextureFormat::UNSIGNED_INT_1010102_REV: 408 case TextureFormat::UNSIGNED_INT_24_8: 409 case TextureFormat::UNSIGNED_INT_999_E5_REV: 410 return getChannelBitDepth(channelType); 411 412 case TextureFormat::HALF_FLOAT: return IVec4(10); 413 case TextureFormat::FLOAT: return IVec4(23); 414 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(6,6,5,0); 415 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(23,8,0,0); 416 default: 417 DE_ASSERT(false); 418 return IVec4(0); 419 } 420 } 421 422 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format) 423 { 424 const IVec4 chnBits = getChannelMantissaBitDepth(format.type); 425 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components; 426 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 427 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 428 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 429 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 430 const IVec4 chnSwz = IVec4((chnMask[0]) ? ((int)map[0]) : (0), 431 (chnMask[1]) ? ((int)map[1]) : (0), 432 (chnMask[2]) ? ((int)map[2]) : (0), 433 (chnMask[3]) ? ((int)map[3]) : (0)); 434 435 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask); 436 } 437 438 BVec4 getTextureFormatChannelMask (const TextureFormat& format) 439 { 440 const TextureSwizzle::Channel* const map = getChannelReadSwizzle(format.order).components; 441 return BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 442 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 443 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 444 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 445 } 446 447 static inline float linearInterpolate (float t, float minVal, float maxVal) 448 { 449 return minVal + (maxVal - minVal) * t; 450 } 451 452 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b) 453 { 454 return a + (b - a) * t; 455 } 456 457 enum 458 { 459 CLEAR_OPTIMIZE_THRESHOLD = 128, 460 CLEAR_OPTIMIZE_MAX_PIXEL_SIZE = 8 461 }; 462 463 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel) 464 { 465 DE_ASSERT(dst.getPixelPitch() == pixelSize); // only tightly packed 466 467 deUint8* dstPtr = (deUint8*)dst.getPixelPtr(0, y, z); 468 int width = dst.getWidth(); 469 470 if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize)) 471 { 472 deUint64 val; 473 memcpy(&val, pixel, sizeof(val)); 474 475 for (int i = 0; i < width; i++) 476 ((deUint64*)dstPtr)[i] = val; 477 } 478 else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize)) 479 { 480 deUint32 val; 481 memcpy(&val, pixel, sizeof(val)); 482 483 for (int i = 0; i < width; i++) 484 ((deUint32*)dstPtr)[i] = val; 485 } 486 else 487 { 488 for (int i = 0; i < width; i++) 489 for (int j = 0; j < pixelSize; j++) 490 dstPtr[i*pixelSize+j] = pixel[j]; 491 } 492 } 493 494 void clear (const PixelBufferAccess& access, const Vec4& color) 495 { 496 const int pixelSize = access.getFormat().getPixelSize(); 497 const int pixelPitch = access.getPixelPitch(); 498 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch); 499 500 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD && 501 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked) 502 { 503 // Convert to destination format. 504 union 505 { 506 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE]; 507 deUint64 u64; // Forces 64-bit alignment. 508 } pixel; 509 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE); 510 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0); 511 512 for (int z = 0; z < access.getDepth(); z++) 513 for (int y = 0; y < access.getHeight(); y++) 514 fillRow(access, y, z, pixelSize, &pixel.u8[0]); 515 } 516 else 517 { 518 for (int z = 0; z < access.getDepth(); z++) 519 for (int y = 0; y < access.getHeight(); y++) 520 for (int x = 0; x < access.getWidth(); x++) 521 access.setPixel(color, x, y, z); 522 } 523 } 524 525 void clear (const PixelBufferAccess& access, const IVec4& color) 526 { 527 const int pixelSize = access.getFormat().getPixelSize(); 528 const int pixelPitch = access.getPixelPitch(); 529 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch); 530 531 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD && 532 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked) 533 { 534 // Convert to destination format. 535 union 536 { 537 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE]; 538 deUint64 u64; // Forces 64-bit alignment. 539 } pixel; 540 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE); 541 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0); 542 543 for (int z = 0; z < access.getDepth(); z++) 544 for (int y = 0; y < access.getHeight(); y++) 545 fillRow(access, y, z, pixelSize, &pixel.u8[0]); 546 } 547 else 548 { 549 for (int z = 0; z < access.getDepth(); z++) 550 for (int y = 0; y < access.getHeight(); y++) 551 for (int x = 0; x < access.getWidth(); x++) 552 access.setPixel(color, x, y, z); 553 } 554 } 555 556 void clear (const PixelBufferAccess& access, const UVec4& color) 557 { 558 clear(access, color.cast<deInt32>()); 559 } 560 561 void clearDepth (const PixelBufferAccess& access, float depth) 562 { 563 DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::D); 564 565 clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_DEPTH), tcu::Vec4(depth, 0.0f, 0.0f, 0.0f)); 566 } 567 568 void clearStencil (const PixelBufferAccess& access, int stencil) 569 { 570 DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::S); 571 572 clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_STENCIL), tcu::UVec4(stencil, 0u, 0u, 0u)); 573 } 574 575 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal) 576 { 577 DE_ASSERT(access.getHeight() == 1); 578 for (int x = 0; x < access.getWidth(); x++) 579 { 580 float s = ((float)x + 0.5f) / (float)access.getWidth(); 581 582 float r = linearInterpolate(s, minVal.x(), maxVal.x()); 583 float g = linearInterpolate(s, minVal.y(), maxVal.y()); 584 float b = linearInterpolate(s, minVal.z(), maxVal.z()); 585 float a = linearInterpolate(s, minVal.w(), maxVal.w()); 586 587 access.setPixel(tcu::Vec4(r, g, b, a), x, 0); 588 } 589 } 590 591 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal) 592 { 593 for (int y = 0; y < access.getHeight(); y++) 594 { 595 for (int x = 0; x < access.getWidth(); x++) 596 { 597 float s = ((float)x + 0.5f) / (float)access.getWidth(); 598 float t = ((float)y + 0.5f) / (float)access.getHeight(); 599 600 float r = linearInterpolate(( s + t) *0.5f, minVal.x(), maxVal.x()); 601 float g = linearInterpolate(( s + (1.0f-t))*0.5f, minVal.y(), maxVal.y()); 602 float b = linearInterpolate(((1.0f-s) + t) *0.5f, minVal.z(), maxVal.z()); 603 float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w()); 604 605 access.setPixel(tcu::Vec4(r, g, b, a), x, y); 606 } 607 } 608 } 609 610 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal) 611 { 612 for (int z = 0; z < dst.getDepth(); z++) 613 { 614 for (int y = 0; y < dst.getHeight(); y++) 615 { 616 for (int x = 0; x < dst.getWidth(); x++) 617 { 618 float s = ((float)x + 0.5f) / (float)dst.getWidth(); 619 float t = ((float)y + 0.5f) / (float)dst.getHeight(); 620 float p = ((float)z + 0.5f) / (float)dst.getDepth(); 621 622 float r = linearInterpolate(s, minVal.x(), maxVal.x()); 623 float g = linearInterpolate(t, minVal.y(), maxVal.y()); 624 float b = linearInterpolate(p, minVal.z(), maxVal.z()); 625 float a = linearInterpolate(1.0f - (s+t+p)/3.0f, minVal.w(), maxVal.w()); 626 627 dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z); 628 } 629 } 630 } 631 } 632 633 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal) 634 { 635 if (isCombinedDepthStencilType(access.getFormat().type)) 636 { 637 const bool hasDepth = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D; 638 const bool hasStencil = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S; 639 640 DE_ASSERT(hasDepth || hasStencil); 641 642 // For combined formats, treat D and S as separate channels 643 if (hasDepth) 644 fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal); 645 if (hasStencil) 646 fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0)); 647 } 648 else 649 { 650 if (access.getHeight() == 1 && access.getDepth() == 1) 651 fillWithComponentGradients1D(access, minVal, maxVal); 652 else if (access.getDepth() == 1) 653 fillWithComponentGradients2D(access, minVal, maxVal); 654 else 655 fillWithComponentGradients3D(access, minVal, maxVal); 656 } 657 } 658 659 static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 660 { 661 for (int x = 0; x < access.getWidth(); x++) 662 { 663 int mx = (x / cellSize) % 2; 664 665 if (mx) 666 access.setPixel(colorB, x, 0); 667 else 668 access.setPixel(colorA, x, 0); 669 } 670 } 671 672 static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 673 { 674 for (int y = 0; y < access.getHeight(); y++) 675 { 676 for (int x = 0; x < access.getWidth(); x++) 677 { 678 int mx = (x / cellSize) % 2; 679 int my = (y / cellSize) % 2; 680 681 if (mx ^ my) 682 access.setPixel(colorB, x, y); 683 else 684 access.setPixel(colorA, x, y); 685 } 686 } 687 } 688 689 static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 690 { 691 for (int z = 0; z < access.getDepth(); z++) 692 { 693 for (int y = 0; y < access.getHeight(); y++) 694 { 695 for (int x = 0; x < access.getWidth(); x++) 696 { 697 int mx = (x / cellSize) % 2; 698 int my = (y / cellSize) % 2; 699 int mz = (z / cellSize) % 2; 700 701 if (mx ^ my ^ mz) 702 access.setPixel(colorB, x, y, z); 703 else 704 access.setPixel(colorA, x, y, z); 705 } 706 } 707 } 708 } 709 710 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 711 { 712 if (isCombinedDepthStencilType(access.getFormat().type)) 713 { 714 const bool hasDepth = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D; 715 const bool hasStencil = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S; 716 717 DE_ASSERT(hasDepth || hasStencil); 718 719 // For combined formats, treat D and S as separate channels 720 if (hasDepth) 721 fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), colorA, colorB); 722 if (hasStencil) 723 fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0)); 724 } 725 else 726 { 727 if (access.getHeight() == 1 && access.getDepth() == 1) 728 fillWithGrid1D(access, cellSize, colorA, colorB); 729 else if (access.getDepth() == 1) 730 fillWithGrid2D(access, cellSize, colorA, colorB); 731 else 732 fillWithGrid3D(access, cellSize, colorA, colorB); 733 } 734 } 735 736 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB) 737 { 738 for (int y = 0; y < access.getHeight(); y++) 739 { 740 for (int x = 0; x < access.getWidth(); x++) 741 { 742 float s = ((float)x + 0.5f) / (float)access.getWidth(); 743 float t = ((float)y + 0.5f) / (float)access.getHeight(); 744 745 float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s; 746 float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t; 747 748 float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f); 749 access.setPixel(linearInterpolate(p, colorA, colorB), x, y); 750 } 751 } 752 } 753 754 void fillWithRGBAQuads (const PixelBufferAccess& dst) 755 { 756 TCU_CHECK_INTERNAL(dst.getDepth() == 1); 757 int width = dst.getWidth(); 758 int height = dst.getHeight(); 759 int left = width/2; 760 int top = height/2; 761 762 clear(getSubregion(dst, 0, 0, 0, left, top, 1), Vec4(1.0f, 0.0f, 0.0f, 1.0f)); 763 clear(getSubregion(dst, left, 0, 0, width-left, top, 1), Vec4(0.0f, 1.0f, 0.0f, 1.0f)); 764 clear(getSubregion(dst, 0, top, 0, left, height-top, 1), Vec4(0.0f, 0.0f, 1.0f, 0.0f)); 765 clear(getSubregion(dst, left, top, 0, width-left, height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f)); 766 } 767 768 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators. 769 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed) 770 { 771 TCU_CHECK_INTERNAL(dst.getDepth() == 1); 772 std::vector<Vec2> points(numBalls); 773 de::Random rnd(seed); 774 775 for (int i = 0; i < numBalls; i++) 776 { 777 float x = rnd.getFloat(); 778 float y = rnd.getFloat(); 779 points[i] = (Vec2(x, y)); 780 } 781 782 for (int y = 0; y < dst.getHeight(); y++) 783 for (int x = 0; x < dst.getWidth(); x++) 784 { 785 Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight()); 786 787 float sum = 0.0f; 788 for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++) 789 { 790 Vec2 d = p - *i; 791 float f = 0.01f / (d.x()*d.x() + d.y()*d.y()); 792 793 sum += f; 794 } 795 796 dst.setPixel(Vec4(sum), x, y); 797 } 798 } 799 800 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src) 801 { 802 DE_ASSERT(src.getSize() == dst.getSize()); 803 804 const int width = dst.getWidth(); 805 const int height = dst.getHeight(); 806 const int depth = dst.getDepth(); 807 808 const int srcPixelSize = src.getFormat().getPixelSize(); 809 const int dstPixelSize = dst.getFormat().getPixelSize(); 810 const int srcPixelPitch = src.getPixelPitch(); 811 const int dstPixelPitch = dst.getPixelPitch(); 812 const bool srcTightlyPacked = (srcPixelSize == srcPixelPitch); 813 const bool dstTightlyPacked = (dstPixelSize == dstPixelPitch); 814 815 const bool srcHasDepth = (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D); 816 const bool srcHasStencil = (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S); 817 const bool dstHasDepth = (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D); 818 const bool dstHasStencil = (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S); 819 820 if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked) 821 { 822 // Fast-path for matching formats. 823 for (int z = 0; z < depth; z++) 824 for (int y = 0; y < height; y++) 825 deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width); 826 } 827 else if (src.getFormat() == dst.getFormat()) 828 { 829 // Bit-exact copy for matching formats. 830 for (int z = 0; z < depth; z++) 831 for (int y = 0; y < height; y++) 832 for (int x = 0; x < width; x++) 833 deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize); 834 } 835 else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil) 836 { 837 DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel 838 839 if (dstHasDepth && srcHasDepth) 840 { 841 for (int z = 0; z < depth; z++) 842 for (int y = 0; y < height; y++) 843 for (int x = 0; x < width; x++) 844 dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z); 845 } 846 else if (dstHasDepth && !srcHasDepth) 847 { 848 // consistency with color copies 849 tcu::clearDepth(dst, 0.0f); 850 } 851 852 if (dstHasStencil && srcHasStencil) 853 { 854 for (int z = 0; z < depth; z++) 855 for (int y = 0; y < height; y++) 856 for (int x = 0; x < width; x++) 857 dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z); 858 } 859 else if (dstHasStencil && !srcHasStencil) 860 { 861 // consistency with color copies 862 tcu::clearStencil(dst, 0u); 863 } 864 } 865 else 866 { 867 TextureChannelClass srcClass = getTextureChannelClass(src.getFormat().type); 868 TextureChannelClass dstClass = getTextureChannelClass(dst.getFormat().type); 869 bool srcIsInt = srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 870 bool dstIsInt = dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 871 872 if (srcIsInt && dstIsInt) 873 { 874 for (int z = 0; z < depth; z++) 875 for (int y = 0; y < height; y++) 876 for (int x = 0; x < width; x++) 877 dst.setPixel(src.getPixelInt(x, y, z), x, y, z); 878 } 879 else 880 { 881 for (int z = 0; z < depth; z++) 882 for (int y = 0; y < height; y++) 883 for (int x = 0; x < width; x++) 884 dst.setPixel(src.getPixel(x, y, z), x, y, z); 885 } 886 } 887 } 888 889 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter) 890 { 891 DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR); 892 893 Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, 894 filter, filter, 0.0f, false); 895 896 float sX = (float)src.getWidth() / (float)dst.getWidth(); 897 float sY = (float)src.getHeight() / (float)dst.getHeight(); 898 float sZ = (float)src.getDepth() / (float)dst.getDepth(); 899 900 if (dst.getDepth() == 1 && src.getDepth() == 1) 901 { 902 for (int y = 0; y < dst.getHeight(); y++) 903 for (int x = 0; x < dst.getWidth(); x++) 904 dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y); 905 } 906 else 907 { 908 for (int z = 0; z < dst.getDepth(); z++) 909 for (int y = 0; y < dst.getHeight(); y++) 910 for (int x = 0; x < dst.getWidth(); x++) 911 dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z); 912 } 913 } 914 915 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal) 916 { 917 const TextureFormat& format = access.getFormat(); 918 919 switch (getTextureChannelClass(format.type)) 920 { 921 case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 922 // Normalized unsigned formats. 923 minVal = Vec4(0.0f); 924 maxVal = Vec4(1.0f); 925 break; 926 927 case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 928 // Normalized signed formats. 929 minVal = Vec4(-1.0f); 930 maxVal = Vec4(+1.0f); 931 break; 932 933 default: 934 // \note Samples every 4/8th pixel. 935 minVal = Vec4(std::numeric_limits<float>::max()); 936 maxVal = Vec4(std::numeric_limits<float>::min()); 937 938 for (int z = 0; z < access.getDepth(); z += 2) 939 { 940 for (int y = 0; y < access.getHeight(); y += 2) 941 { 942 for (int x = 0; x < access.getWidth(); x += 2) 943 { 944 Vec4 p = access.getPixel(x, y, z); 945 946 minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0])); 947 minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1])); 948 minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2])); 949 minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3])); 950 951 maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0])); 952 maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1])); 953 maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2])); 954 maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3])); 955 } 956 } 957 } 958 break; 959 } 960 } 961 962 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias) 963 { 964 Vec4 minVal, maxVal; 965 estimatePixelValueRange(access, minVal, maxVal); 966 967 const float eps = 0.0001f; 968 969 for (int c = 0; c < 4; c++) 970 { 971 if (maxVal[c] - minVal[c] < eps) 972 { 973 scale[c] = (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]); 974 bias[c] = (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]); 975 } 976 else 977 { 978 scale[c] = 1.0f / (maxVal[c] - minVal[c]); 979 bias[c] = 0.0f - minVal[c]*scale[c]; 980 } 981 } 982 } 983 984 int getCubeArrayFaceIndex (CubeFace face) 985 { 986 DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST); 987 988 switch (face) 989 { 990 case CUBEFACE_POSITIVE_X: return 0; 991 case CUBEFACE_NEGATIVE_X: return 1; 992 case CUBEFACE_POSITIVE_Y: return 2; 993 case CUBEFACE_NEGATIVE_Y: return 3; 994 case CUBEFACE_POSITIVE_Z: return 4; 995 case CUBEFACE_NEGATIVE_Z: return 5; 996 997 default: 998 return -1; 999 } 1000 } 1001 1002 deUint32 packRGB999E5 (const tcu::Vec4& color) 1003 { 1004 const int mBits = 9; 1005 const int eBits = 5; 1006 const int eBias = 15; 1007 const int eMax = (1<<eBits)-1; 1008 const float maxVal = (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits); 1009 1010 float rc = deFloatClamp(color[0], 0.0f, maxVal); 1011 float gc = deFloatClamp(color[1], 0.0f, maxVal); 1012 float bc = deFloatClamp(color[2], 0.0f, maxVal); 1013 float maxc = de::max(rc, de::max(gc, bc)); 1014 int expp = de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias; 1015 float e = deFloatPow(2.0f, (float)(expp-eBias-mBits)); 1016 int maxs = deFloorFloatToInt32(maxc / e + 0.5f); 1017 1018 deUint32 exps = maxs == (1<<mBits) ? expp+1 : expp; 1019 deUint32 rs = (deUint32)deClamp32(deFloorFloatToInt32(rc / e + 0.5f), 0, (1<<9)-1); 1020 deUint32 gs = (deUint32)deClamp32(deFloorFloatToInt32(gc / e + 0.5f), 0, (1<<9)-1); 1021 deUint32 bs = (deUint32)deClamp32(deFloorFloatToInt32(bc / e + 0.5f), 0, (1<<9)-1); 1022 1023 DE_ASSERT((exps & ~((1<<5)-1)) == 0); 1024 DE_ASSERT((rs & ~((1<<9)-1)) == 0); 1025 DE_ASSERT((gs & ~((1<<9)-1)) == 0); 1026 DE_ASSERT((bs & ~((1<<9)-1)) == 0); 1027 1028 return rs | (gs << 9) | (bs << 18) | (exps << 27); 1029 } 1030 1031 // Sampler utils 1032 1033 static const void* addOffset (const void* ptr, int numBytes) 1034 { 1035 return (const deUint8*)ptr + numBytes; 1036 } 1037 1038 static void* addOffset (void* ptr, int numBytes) 1039 { 1040 return (deUint8*)ptr + numBytes; 1041 } 1042 1043 template <typename AccessType> 1044 static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode) 1045 { 1046 // make sure to update this if type table is updated 1047 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 27); 1048 1049 if (!isCombinedDepthStencilType(baseAccess.getFormat().type)) 1050 return baseAccess; 1051 else 1052 { 1053 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN) 1054 const deUint32 uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address 1055 const deUint32 uint32ByteOffset8To32 = 1; 1056 #else 1057 const deUint32 uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address 1058 const deUint32 uint32ByteOffset8To32 = 0; 1059 #endif 1060 1061 // Sampled channel must exist 1062 DE_ASSERT(baseAccess.getFormat().order == TextureFormat::DS || 1063 (mode == Sampler::MODE_DEPTH && baseAccess.getFormat().order == TextureFormat::D) || 1064 (mode == Sampler::MODE_STENCIL && baseAccess.getFormat().order == TextureFormat::S)); 1065 1066 // combined formats have multiple channel classes, detect on sampler settings 1067 switch (baseAccess.getFormat().type) 1068 { 1069 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: 1070 { 1071 if (mode == Sampler::MODE_DEPTH) 1072 { 1073 // select the float component 1074 return AccessType(TextureFormat(TextureFormat::D, TextureFormat::FLOAT), 1075 baseAccess.getSize(), 1076 baseAccess.getPitch(), 1077 baseAccess.getDataPtr()); 1078 } 1079 else if (mode == Sampler::MODE_STENCIL) 1080 { 1081 // select the uint 8 component 1082 return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), 1083 baseAccess.getSize(), 1084 baseAccess.getPitch(), 1085 addOffset(baseAccess.getDataPtr(), 4 + uint32ByteOffsetBits0To8)); 1086 } 1087 else 1088 { 1089 // unknown sampler mode 1090 DE_ASSERT(false); 1091 return AccessType(); 1092 } 1093 } 1094 1095 case TextureFormat::UNSIGNED_INT_24_8: 1096 { 1097 if (mode == Sampler::MODE_DEPTH) 1098 { 1099 // select the unorm24 component 1100 return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24), 1101 baseAccess.getSize(), 1102 baseAccess.getPitch(), 1103 addOffset(baseAccess.getDataPtr(), uint32ByteOffset8To32)); 1104 } 1105 else if (mode == Sampler::MODE_STENCIL) 1106 { 1107 // select the uint 8 component 1108 return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), 1109 baseAccess.getSize(), 1110 baseAccess.getPitch(), 1111 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8)); 1112 } 1113 else 1114 { 1115 // unknown sampler mode 1116 DE_ASSERT(false); 1117 return AccessType(); 1118 } 1119 } 1120 1121 default: 1122 { 1123 // unknown combined format 1124 DE_ASSERT(false); 1125 return AccessType(); 1126 } 1127 } 1128 } 1129 } 1130 1131 PixelBufferAccess getEffectiveDepthStencilAccess (const PixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode) 1132 { 1133 return toSamplerAccess<PixelBufferAccess>(baseAccess, mode); 1134 } 1135 1136 ConstPixelBufferAccess getEffectiveDepthStencilAccess (const ConstPixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode) 1137 { 1138 return toSamplerAccess<ConstPixelBufferAccess>(baseAccess, mode); 1139 } 1140 1141 TextureFormat getEffectiveDepthStencilTextureFormat (const TextureFormat& baseFormat, Sampler::DepthStencilMode mode) 1142 { 1143 return toSamplerAccess(ConstPixelBufferAccess(baseFormat, IVec3(0, 0, 0), DE_NULL), mode).getFormat(); 1144 } 1145 1146 template <typename ViewType> 1147 ViewType getEffectiveTView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1148 { 1149 storage.resize(src.getNumLevels()); 1150 1151 ViewType view = ViewType(src.getNumLevels(), &storage[0]); 1152 1153 for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx) 1154 storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode); 1155 1156 return view; 1157 } 1158 1159 tcu::TextureCubeView getEffectiveTView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1160 { 1161 storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels()); 1162 1163 const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] = 1164 { 1165 &storage[0 * src.getNumLevels()], 1166 &storage[1 * src.getNumLevels()], 1167 &storage[2 * src.getNumLevels()], 1168 &storage[3 * src.getNumLevels()], 1169 &storage[4 * src.getNumLevels()], 1170 &storage[5 * src.getNumLevels()], 1171 }; 1172 1173 tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs); 1174 1175 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx) 1176 for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx) 1177 storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode); 1178 1179 return view; 1180 } 1181 1182 tcu::Texture1DView getEffectiveTextureView (const tcu::Texture1DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1183 { 1184 return getEffectiveTView(src, storage, sampler); 1185 } 1186 1187 tcu::Texture2DView getEffectiveTextureView (const tcu::Texture2DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1188 { 1189 return getEffectiveTView(src, storage, sampler); 1190 } 1191 1192 tcu::Texture3DView getEffectiveTextureView (const tcu::Texture3DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1193 { 1194 return getEffectiveTView(src, storage, sampler); 1195 } 1196 1197 tcu::Texture1DArrayView getEffectiveTextureView (const tcu::Texture1DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1198 { 1199 return getEffectiveTView(src, storage, sampler); 1200 } 1201 1202 tcu::Texture2DArrayView getEffectiveTextureView (const tcu::Texture2DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1203 { 1204 return getEffectiveTView(src, storage, sampler); 1205 } 1206 1207 tcu::TextureCubeView getEffectiveTextureView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1208 { 1209 return getEffectiveTView(src, storage, sampler); 1210 } 1211 1212 tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 1213 { 1214 return getEffectiveTView(src, storage, sampler); 1215 } 1216 1217 //! Returns the effective swizzle of a border color. The effective swizzle is the 1218 //! equal to first writing an RGBA color with a write swizzle and then reading 1219 //! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C)) 1220 static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order) 1221 { 1222 // make sure to update these tables when channel orders are updated 1223 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 18); 1224 1225 static const TextureSwizzle INV = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }}; 1226 static const TextureSwizzle R = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }}; 1227 static const TextureSwizzle A = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_3 }}; 1228 static const TextureSwizzle I = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0 }}; 1229 static const TextureSwizzle L = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE }}; 1230 static const TextureSwizzle LA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3 }}; 1231 static const TextureSwizzle RG = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }}; 1232 static const TextureSwizzle RA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_3 }}; 1233 static const TextureSwizzle RGB = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_ONE }}; 1234 static const TextureSwizzle RGBA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3 }}; 1235 static const TextureSwizzle D = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }}; 1236 static const TextureSwizzle S = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }}; 1237 1238 const TextureSwizzle* swizzle; 1239 1240 switch (order) 1241 { 1242 case TextureFormat::R: swizzle = &R; break; 1243 case TextureFormat::A: swizzle = &A; break; 1244 case TextureFormat::I: swizzle = &I; break; 1245 case TextureFormat::L: swizzle = &L; break; 1246 case TextureFormat::LA: swizzle = &LA; break; 1247 case TextureFormat::RG: swizzle = &RG; break; 1248 case TextureFormat::RA: swizzle = &RA; break; 1249 case TextureFormat::RGB: swizzle = &RGB; break; 1250 case TextureFormat::RGBA: swizzle = &RGBA; break; 1251 case TextureFormat::ARGB: swizzle = &RGBA; break; 1252 case TextureFormat::BGRA: swizzle = &RGBA; break; 1253 case TextureFormat::sR: swizzle = &R; break; 1254 case TextureFormat::sRG: swizzle = &RG; break; 1255 case TextureFormat::sRGB: swizzle = &RGB; break; 1256 case TextureFormat::sRGBA: swizzle = &RGBA; break; 1257 case TextureFormat::D: swizzle = &D; break; 1258 case TextureFormat::S: swizzle = &S; break; 1259 1260 case TextureFormat::DS: 1261 DE_ASSERT(false); // combined depth-stencil border color? 1262 swizzle = &INV; 1263 break; 1264 1265 default: 1266 DE_ASSERT(false); 1267 swizzle = &INV; 1268 break; 1269 } 1270 1271 #ifdef DE_DEBUG 1272 1273 { 1274 // check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C)) 1275 const TextureSwizzle& readSwizzle = getChannelReadSwizzle(order); 1276 const TextureSwizzle& writeSwizzle = getChannelWriteSwizzle(order); 1277 1278 for (int ndx = 0; ndx < 4; ++ndx) 1279 { 1280 TextureSwizzle::Channel writeRead = readSwizzle.components[ndx]; 1281 if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE) 1282 writeRead = writeSwizzle.components[(int)writeRead]; 1283 DE_ASSERT(writeRead == swizzle->components[ndx]); 1284 } 1285 } 1286 1287 #endif 1288 1289 return *swizzle; 1290 } 1291 1292 static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits) 1293 { 1294 return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0), 1295 (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0), 1296 (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0), 1297 (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0)); 1298 } 1299 1300 static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits) 1301 { 1302 return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0), 1303 (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0), 1304 (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0), 1305 (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0)); 1306 } 1307 1308 static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits) 1309 { 1310 return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0), 1311 (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0), 1312 (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0), 1313 (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0)); 1314 } 1315 1316 static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler) 1317 { 1318 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type); 1319 const TextureSwizzle::Channel* channelMap = getBorderColorReadSwizzle(format.order).components; 1320 const bool isFloat = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT; 1321 const bool isSigned = channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 1322 const float valueMin = (isSigned) ? (-1.0f) : (0.0f); 1323 const float valueMax = 1.0f; 1324 Vec4 result; 1325 1326 DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || 1327 channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || 1328 channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT); 1329 1330 for (int c = 0; c < 4; c++) 1331 { 1332 const TextureSwizzle::Channel map = channelMap[c]; 1333 if (map == TextureSwizzle::CHANNEL_ZERO) 1334 result[c] = 0.0f; 1335 else if (map == TextureSwizzle::CHANNEL_ONE) 1336 result[c] = 1.0f; 1337 else if (isFloat) 1338 { 1339 // floating point values are not clamped 1340 result[c] = sampler.borderColor.getAccess<float>()[(int)map]; 1341 } 1342 else 1343 { 1344 // fixed point values are clamped to a representable range 1345 result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax); 1346 } 1347 } 1348 1349 return result; 1350 } 1351 1352 static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler) 1353 { 1354 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type); 1355 const TextureSwizzle::Channel* channelMap = getBorderColorReadSwizzle(format.order).components; 1356 const IVec4 channelBits = getChannelBitDepth(format.type); 1357 const IVec4 valueMin = getNBitSignedIntegerVec4MinValue(channelBits); 1358 const IVec4 valueMax = getNBitSignedIntegerVec4MaxValue(channelBits); 1359 IVec4 result; 1360 1361 DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER); 1362 DE_UNREF(channelClass); 1363 1364 for (int c = 0; c < 4; c++) 1365 { 1366 const TextureSwizzle::Channel map = channelMap[c]; 1367 if (map == TextureSwizzle::CHANNEL_ZERO) 1368 result[c] = 0; 1369 else if (map == TextureSwizzle::CHANNEL_ONE) 1370 result[c] = 1; 1371 else 1372 { 1373 // integer values are clamped to a representable range 1374 result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]); 1375 } 1376 } 1377 1378 return result; 1379 } 1380 1381 static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler) 1382 { 1383 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type); 1384 const TextureSwizzle::Channel* channelMap = getBorderColorReadSwizzle(format.order).components; 1385 const IVec4 channelBits = getChannelBitDepth(format.type); 1386 const UVec4 valueMax = getNBitUnsignedIntegerVec4MaxValue(channelBits); 1387 UVec4 result; 1388 1389 DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER); 1390 DE_UNREF(channelClass); 1391 1392 for (int c = 0; c < 4; c++) 1393 { 1394 const TextureSwizzle::Channel map = channelMap[c]; 1395 if (map == TextureSwizzle::CHANNEL_ZERO) 1396 result[c] = 0; 1397 else if (map == TextureSwizzle::CHANNEL_ONE) 1398 result[c] = 1; 1399 else 1400 { 1401 // integer values are clamped to a representable range 1402 result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]); 1403 } 1404 } 1405 1406 return result; 1407 } 1408 1409 template <typename ScalarType> 1410 tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler) 1411 { 1412 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type); 1413 1414 switch (channelClass) 1415 { 1416 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 1417 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 1418 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 1419 return getTextureBorderColorFloat(format, sampler).cast<ScalarType>(); 1420 1421 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 1422 return getTextureBorderColorInt(format, sampler).cast<ScalarType>(); 1423 1424 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 1425 return getTextureBorderColorUint(format, sampler).cast<ScalarType>(); 1426 1427 default: 1428 DE_ASSERT(false); 1429 return tcu::Vector<ScalarType, 4>(); 1430 } 1431 } 1432 1433 // instantiation 1434 template tcu::Vector<float, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler); 1435 template tcu::Vector<deInt32, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler); 1436 template tcu::Vector<deUint32, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler); 1437 1438 } // tcu 1439