tcuTextureUtil.cpp revision 6c307165131fb7249bb044fc79ff0c2747263b3d
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 32namespace tcu 33{ 34 35static 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 43static 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 56Vec4 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 65Vec4 linearToSRGB (const Vec4& cl) 66{ 67 return Vec4(linearChannelToSRGB(cl[0]), 68 linearChannelToSRGB(cl[1]), 69 linearChannelToSRGB(cl[2]), 70 cl[3]); 71} 72 73bool 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//! Get texture channel class for format 82TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType) 83{ 84 // make sure this table is updated if format table is updated 85 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 26); 86 87 switch (channelType) 88 { 89 case TextureFormat::SNORM_INT8: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT; 90 case TextureFormat::SNORM_INT16: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT; 91 case TextureFormat::SNORM_INT32: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT; 92 case TextureFormat::UNORM_INT8: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 93 case TextureFormat::UNORM_INT16: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 94 case TextureFormat::UNORM_INT24: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 95 case TextureFormat::UNORM_INT32: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 96 case TextureFormat::UNORM_SHORT_565: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 97 case TextureFormat::UNORM_SHORT_555: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 98 case TextureFormat::UNORM_SHORT_4444: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 99 case TextureFormat::UNORM_SHORT_5551: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 100 case TextureFormat::UNORM_INT_101010: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 101 case TextureFormat::UNORM_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 102 case TextureFormat::UNSIGNED_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 103 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return TEXTURECHANNELCLASS_FLOATING_POINT; 104 case TextureFormat::UNSIGNED_INT_999_E5_REV: return TEXTURECHANNELCLASS_FLOATING_POINT; 105 case TextureFormat::UNSIGNED_INT_24_8: return TEXTURECHANNELCLASS_LAST; //!< packed unorm24-uint8 106 case TextureFormat::SIGNED_INT8: return TEXTURECHANNELCLASS_SIGNED_INTEGER; 107 case TextureFormat::SIGNED_INT16: return TEXTURECHANNELCLASS_SIGNED_INTEGER; 108 case TextureFormat::SIGNED_INT32: return TEXTURECHANNELCLASS_SIGNED_INTEGER; 109 case TextureFormat::UNSIGNED_INT8: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 110 case TextureFormat::UNSIGNED_INT16: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 111 case TextureFormat::UNSIGNED_INT32: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 112 case TextureFormat::HALF_FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT; 113 case TextureFormat::FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT; 114 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return TEXTURECHANNELCLASS_LAST; //!< packed float32-pad24-uint8 115 default: return TEXTURECHANNELCLASS_LAST; 116 } 117} 118 119/*--------------------------------------------------------------------*//*! 120 * \brief Get access to subregion of pixel buffer 121 * \param access Parent access object 122 * \param x X offset 123 * \param y Y offset 124 * \param z Z offset 125 * \param width Width 126 * \param height Height 127 * \param depth Depth 128 * \return Access object that targets given subregion of parent access object 129 *//*--------------------------------------------------------------------*/ 130ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth) 131{ 132 DE_ASSERT(de::inBounds(x, 0, access.getWidth())); 133 DE_ASSERT(de::inRange(x+width, x+1, access.getWidth())); 134 135 DE_ASSERT(de::inBounds(y, 0, access.getHeight())); 136 DE_ASSERT(de::inRange(y+height, y+1, access.getHeight())); 137 138 DE_ASSERT(de::inBounds(z, 0, access.getDepth())); 139 DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth())); 140 141 return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(), 142 (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z); 143} 144 145/*--------------------------------------------------------------------*//*! 146 * \brief Get access to subregion of pixel buffer 147 * \param access Parent access object 148 * \param x X offset 149 * \param y Y offset 150 * \param z Z offset 151 * \param width Width 152 * \param height Height 153 * \param depth Depth 154 * \return Access object that targets given subregion of parent access object 155 *//*--------------------------------------------------------------------*/ 156PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth) 157{ 158 DE_ASSERT(de::inBounds(x, 0, access.getWidth())); 159 DE_ASSERT(de::inRange(x+width, x+1, access.getWidth())); 160 161 DE_ASSERT(de::inBounds(y, 0, access.getHeight())); 162 DE_ASSERT(de::inRange(y+height, y+1, access.getHeight())); 163 164 DE_ASSERT(de::inBounds(z, 0, access.getDepth())); 165 DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth())); 166 167 return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(), 168 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z); 169} 170 171/*--------------------------------------------------------------------*//*! 172 * \brief Get access to subregion of pixel buffer 173 * \param access Parent access object 174 * \param x X offset 175 * \param y Y offset 176 * \param width Width 177 * \param height Height 178 * \return Access object that targets given subregion of parent access object 179 *//*--------------------------------------------------------------------*/ 180PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height) 181{ 182 return getSubregion(access, x, y, 0, width, height, 1); 183} 184 185/*--------------------------------------------------------------------*//*! 186 * \brief Get access to subregion of pixel buffer 187 * \param access Parent access object 188 * \param x X offset 189 * \param y Y offset 190 * \param width Width 191 * \param height Height 192 * \return Access object that targets given subregion of parent access object 193 *//*--------------------------------------------------------------------*/ 194ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height) 195{ 196 return getSubregion(access, x, y, 0, width, height, 1); 197} 198 199/*--------------------------------------------------------------------*//*! 200 * \brief Flip rows in Y direction 201 * \param access Access object 202 * \return Modified access object where Y coordinates are reversed 203 *//*--------------------------------------------------------------------*/ 204PixelBufferAccess flipYAccess (const PixelBufferAccess& access) 205{ 206 const int rowPitch = access.getRowPitch(); 207 const int offsetToLast = rowPitch*(access.getHeight()-1); 208 const tcu::IVec3 pitch (access.getPixelPitch(), -rowPitch, access.getSlicePitch()); 209 210 return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast); 211} 212 213/*--------------------------------------------------------------------*//*! 214 * \brief Flip rows in Y direction 215 * \param access Access object 216 * \return Modified access object where Y coordinates are reversed 217 *//*--------------------------------------------------------------------*/ 218ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access) 219{ 220 const int rowPitch = access.getRowPitch(); 221 const int offsetToLast = rowPitch*(access.getHeight()-1); 222 const tcu::IVec3 pitch (access.getPixelPitch(), -rowPitch, access.getSlicePitch()); 223 224 return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast); 225} 226 227static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType) 228{ 229 // make sure this table is updated if format table is updated 230 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 26); 231 232 float cMin = 0.0f; 233 float cMax = 0.0f; 234 235 switch (channelType) 236 { 237 // Signed normalized formats. 238 case TextureFormat::SNORM_INT8: 239 case TextureFormat::SNORM_INT16: 240 case TextureFormat::SNORM_INT32: cMin = -1.0f; cMax = 1.0f; break; 241 242 // Unsigned normalized formats. 243 case TextureFormat::UNORM_INT8: 244 case TextureFormat::UNORM_INT16: 245 case TextureFormat::UNORM_INT24: 246 case TextureFormat::UNORM_INT32: 247 case TextureFormat::UNORM_SHORT_565: 248 case TextureFormat::UNORM_SHORT_4444: 249 case TextureFormat::UNORM_INT_101010: 250 case TextureFormat::UNORM_INT_1010102_REV: cMin = 0.0f; cMax = 1.0f; break; 251 252 // Misc formats. 253 case TextureFormat::SIGNED_INT8: cMin = -128.0f; cMax = 127.0f; break; 254 case TextureFormat::SIGNED_INT16: cMin = -32768.0f; cMax = 32767.0f; break; 255 case TextureFormat::SIGNED_INT32: cMin = -2147483648.0f; cMax = 2147483647.0f; break; 256 case TextureFormat::UNSIGNED_INT8: cMin = 0.0f; cMax = 255.0f; break; 257 case TextureFormat::UNSIGNED_INT16: cMin = 0.0f; cMax = 65535.0f; break; 258 case TextureFormat::UNSIGNED_INT32: cMin = 0.0f; cMax = 4294967295.f; break; 259 case TextureFormat::HALF_FLOAT: cMin = -1e3f; cMax = 1e3f; break; 260 case TextureFormat::FLOAT: cMin = -1e5f; cMax = 1e5f; break; 261 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: cMin = 0.0f; cMax = 1e4f; break; 262 case TextureFormat::UNSIGNED_INT_999_E5_REV: cMin = 0.0f; cMax = 1e5f; break; 263 264 default: 265 DE_ASSERT(false); 266 } 267 268 return Vec2(cMin, cMax); 269} 270 271/*--------------------------------------------------------------------*//*! 272 * \brief Get standard parameters for testing texture format 273 * 274 * Returns TextureFormatInfo that describes good parameters for exercising 275 * given TextureFormat. Parameters include value ranges per channel and 276 * suitable lookup scaling and bias in order to reduce result back to 277 * 0..1 range. 278 *//*--------------------------------------------------------------------*/ 279TextureFormatInfo getTextureFormatInfo (const TextureFormat& format) 280{ 281 // Special cases. 282 if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV)) 283 return TextureFormatInfo(Vec4( 0.0f, 0.0f, 0.0f, 0.0f), 284 Vec4( 1023.0f, 1023.0f, 1023.0f, 3.0f), 285 Vec4(1.0f/1023.f, 1.0f/1023.0f, 1.0f/1023.0f, 1.0f/3.0f), 286 Vec4( 0.0f, 0.0f, 0.0f, 0.0f)); 287 else if (format.order == TextureFormat::D || format.order == TextureFormat::DS) 288 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.0f), 289 Vec4(1.0f, 1.0f, 1.0f, 0.0f), 290 Vec4(1.0f, 1.0f, 1.0f, 1.0f), 291 Vec4(0.0f, 0.0f, 0.0f, 0.0f)); // Depth / stencil formats. 292 else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551)) 293 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f), 294 Vec4(1.0f, 1.0f, 1.0f, 1.5f), 295 Vec4(1.0f, 1.0f, 1.0f, 1.0f), 296 Vec4(0.0f, 0.0f, 0.0f, 0.0f)); 297 298 const Vec2 cRange = getChannelValueRange(format.type); 299 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components; 300 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 301 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 302 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 303 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 304 const float scale = 1.0f / (cRange[1] - cRange[0]); 305 const float bias = -cRange[0] * scale; 306 307 return TextureFormatInfo(select(cRange[0], 0.0f, chnMask), 308 select(cRange[1], 0.0f, chnMask), 309 select(scale, 1.0f, chnMask), 310 select(bias, 0.0f, chnMask)); 311} 312 313static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType) 314{ 315 // make sure this table is updated if format table is updated 316 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 26); 317 318 switch (channelType) 319 { 320 case TextureFormat::SNORM_INT8: return IVec4(8); 321 case TextureFormat::SNORM_INT16: return IVec4(16); 322 case TextureFormat::SNORM_INT32: return IVec4(32); 323 case TextureFormat::UNORM_INT8: return IVec4(8); 324 case TextureFormat::UNORM_INT16: return IVec4(16); 325 case TextureFormat::UNORM_INT24: return IVec4(24); 326 case TextureFormat::UNORM_INT32: return IVec4(32); 327 case TextureFormat::UNORM_SHORT_565: return IVec4(5,6,5,0); 328 case TextureFormat::UNORM_SHORT_4444: return IVec4(4); 329 case TextureFormat::UNORM_SHORT_555: return IVec4(5,5,5,0); 330 case TextureFormat::UNORM_SHORT_5551: return IVec4(5,5,5,1); 331 case TextureFormat::UNORM_INT_101010: return IVec4(10,10,10,0); 332 case TextureFormat::UNORM_INT_1010102_REV: return IVec4(10,10,10,2); 333 case TextureFormat::SIGNED_INT8: return IVec4(8); 334 case TextureFormat::SIGNED_INT16: return IVec4(16); 335 case TextureFormat::SIGNED_INT32: return IVec4(32); 336 case TextureFormat::UNSIGNED_INT8: return IVec4(8); 337 case TextureFormat::UNSIGNED_INT16: return IVec4(16); 338 case TextureFormat::UNSIGNED_INT32: return IVec4(32); 339 case TextureFormat::UNSIGNED_INT_1010102_REV: return IVec4(10,10,10,2); 340 case TextureFormat::UNSIGNED_INT_24_8: return IVec4(24,8,0,0); 341 case TextureFormat::HALF_FLOAT: return IVec4(16); 342 case TextureFormat::FLOAT: return IVec4(32); 343 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(11,11,10,0); 344 case TextureFormat::UNSIGNED_INT_999_E5_REV: return IVec4(9,9,9,0); 345 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(32,8,0,0); 346 default: 347 DE_ASSERT(false); 348 return IVec4(0); 349 } 350} 351 352IVec4 getTextureFormatBitDepth (const TextureFormat& format) 353{ 354 const IVec4 chnBits = getChannelBitDepth(format.type); 355 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components; 356 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 357 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 358 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 359 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 360 const IVec4 chnSwz = IVec4((chnMask[0]) ? ((int)map[0]) : (0), 361 (chnMask[1]) ? ((int)map[1]) : (0), 362 (chnMask[2]) ? ((int)map[2]) : (0), 363 (chnMask[3]) ? ((int)map[3]) : (0)); 364 365 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask); 366} 367 368static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType) 369{ 370 // make sure this table is updated if format table is updated 371 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 26); 372 373 switch (channelType) 374 { 375 case TextureFormat::SNORM_INT8: 376 case TextureFormat::SNORM_INT16: 377 case TextureFormat::SNORM_INT32: 378 case TextureFormat::UNORM_INT8: 379 case TextureFormat::UNORM_INT16: 380 case TextureFormat::UNORM_INT24: 381 case TextureFormat::UNORM_INT32: 382 case TextureFormat::UNORM_SHORT_565: 383 case TextureFormat::UNORM_SHORT_4444: 384 case TextureFormat::UNORM_SHORT_555: 385 case TextureFormat::UNORM_SHORT_5551: 386 case TextureFormat::UNORM_INT_101010: 387 case TextureFormat::UNORM_INT_1010102_REV: 388 case TextureFormat::SIGNED_INT8: 389 case TextureFormat::SIGNED_INT16: 390 case TextureFormat::SIGNED_INT32: 391 case TextureFormat::UNSIGNED_INT8: 392 case TextureFormat::UNSIGNED_INT16: 393 case TextureFormat::UNSIGNED_INT32: 394 case TextureFormat::UNSIGNED_INT_1010102_REV: 395 case TextureFormat::UNSIGNED_INT_24_8: 396 case TextureFormat::UNSIGNED_INT_999_E5_REV: 397 return getChannelBitDepth(channelType); 398 399 case TextureFormat::HALF_FLOAT: return IVec4(10); 400 case TextureFormat::FLOAT: return IVec4(23); 401 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(6,6,5,0); 402 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(23,8,0,0); 403 default: 404 DE_ASSERT(false); 405 return IVec4(0); 406 } 407} 408 409IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format) 410{ 411 const IVec4 chnBits = getChannelMantissaBitDepth(format.type); 412 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components; 413 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 414 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 415 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE, 416 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE); 417 const IVec4 chnSwz = IVec4((chnMask[0]) ? ((int)map[0]) : (0), 418 (chnMask[1]) ? ((int)map[1]) : (0), 419 (chnMask[2]) ? ((int)map[2]) : (0), 420 (chnMask[3]) ? ((int)map[3]) : (0)); 421 422 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask); 423} 424 425static inline float linearInterpolate (float t, float minVal, float maxVal) 426{ 427 return minVal + (maxVal - minVal) * t; 428} 429 430static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b) 431{ 432 return a + (b - a) * t; 433} 434 435enum 436{ 437 CLEAR_OPTIMIZE_THRESHOLD = 128, 438 CLEAR_OPTIMIZE_MAX_PIXEL_SIZE = 8 439}; 440 441inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel) 442{ 443 deUint8* dstPtr = (deUint8*)dst.getDataPtr() + z*dst.getSlicePitch() + y*dst.getRowPitch(); 444 int width = dst.getWidth(); 445 446 if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize) && deIsAlignedPtr(dstPtr, pixelSize)) 447 { 448 deUint64 val; 449 memcpy(&val, pixel, sizeof(val)); 450 451 for (int i = 0; i < width; i++) 452 ((deUint64*)dstPtr)[i] = val; 453 } 454 else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize) && deIsAlignedPtr(dstPtr, pixelSize)) 455 { 456 deUint32 val; 457 memcpy(&val, pixel, sizeof(val)); 458 459 for (int i = 0; i < width; i++) 460 ((deUint32*)dstPtr)[i] = val; 461 } 462 else 463 { 464 for (int i = 0; i < width; i++) 465 for (int j = 0; j < pixelSize; j++) 466 dstPtr[i*pixelSize+j] = pixel[j]; 467 } 468} 469 470void clear (const PixelBufferAccess& access, const Vec4& color) 471{ 472 const int pixelSize = access.getFormat().getPixelSize(); 473 const int pixelPitch = access.getPixelPitch(); 474 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch); 475 476 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD && 477 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked) 478 { 479 // Convert to destination format. 480 union 481 { 482 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE]; 483 deUint64 u64; // Forces 64-bit alignment. 484 } pixel; 485 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE); 486 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0); 487 488 for (int z = 0; z < access.getDepth(); z++) 489 for (int y = 0; y < access.getHeight(); y++) 490 fillRow(access, y, z, pixelSize, &pixel.u8[0]); 491 } 492 else 493 { 494 for (int z = 0; z < access.getDepth(); z++) 495 for (int y = 0; y < access.getHeight(); y++) 496 for (int x = 0; x < access.getWidth(); x++) 497 access.setPixel(color, x, y, z); 498 } 499} 500 501void clear (const PixelBufferAccess& access, const IVec4& color) 502{ 503 const int pixelSize = access.getFormat().getPixelSize(); 504 const int pixelPitch = access.getPixelPitch(); 505 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch); 506 507 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD && 508 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked) 509 { 510 // Convert to destination format. 511 union 512 { 513 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE]; 514 deUint64 u64; // Forces 64-bit alignment. 515 } pixel; 516 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE); 517 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0); 518 519 for (int z = 0; z < access.getDepth(); z++) 520 for (int y = 0; y < access.getHeight(); y++) 521 fillRow(access, y, z, pixelSize, &pixel.u8[0]); 522 } 523 else 524 { 525 for (int z = 0; z < access.getDepth(); z++) 526 for (int y = 0; y < access.getHeight(); y++) 527 for (int x = 0; x < access.getWidth(); x++) 528 access.setPixel(color, x, y, z); 529 } 530} 531 532void clear (const PixelBufferAccess& access, const UVec4& color) 533{ 534 clear(access, color.cast<deInt32>()); 535} 536 537void clearDepth (const PixelBufferAccess& access, float depth) 538{ 539 const int pixelSize = access.getFormat().getPixelSize(); 540 const int pixelPitch = access.getPixelPitch(); 541 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch); 542 543 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD && 544 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked) 545 { 546 // Convert to destination format. 547 union 548 { 549 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE]; 550 deUint64 u64; // Forces 64-bit alignment. 551 } pixel; 552 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE); 553 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixDepth(depth, 0, 0); 554 555 for (int z = 0; z < access.getDepth(); z++) 556 for (int y = 0; y < access.getHeight(); y++) 557 fillRow(access, y, z, pixelSize, &pixel.u8[0]); 558 } 559 else 560 { 561 for (int z = 0; z < access.getDepth(); z++) 562 for (int y = 0; y < access.getHeight(); y++) 563 for (int x = 0; x < access.getWidth(); x++) 564 access.setPixDepth(depth, x, y, z); 565 } 566} 567 568void clearStencil (const PixelBufferAccess& access, int stencil) 569{ 570 const int pixelSize = access.getFormat().getPixelSize(); 571 const int pixelPitch = access.getPixelPitch(); 572 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch); 573 574 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD && 575 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked) 576 { 577 // Convert to destination format. 578 union 579 { 580 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE]; 581 deUint64 u64; // Forces 64-bit alignment. 582 } pixel; 583 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE); 584 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixStencil(stencil, 0, 0); 585 586 for (int z = 0; z < access.getDepth(); z++) 587 for (int y = 0; y < access.getHeight(); y++) 588 fillRow(access, y, z, pixelSize, &pixel.u8[0]); 589 } 590 else 591 { 592 for (int z = 0; z < access.getDepth(); z++) 593 for (int y = 0; y < access.getHeight(); y++) 594 for (int x = 0; x < access.getWidth(); x++) 595 access.setPixStencil(stencil, x, y, z); 596 } 597} 598 599static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal) 600{ 601 DE_ASSERT(access.getHeight() == 1); 602 for (int x = 0; x < access.getWidth(); x++) 603 { 604 float s = ((float)x + 0.5f) / (float)access.getWidth(); 605 606 float r = linearInterpolate(s, minVal.x(), maxVal.x()); 607 float g = linearInterpolate(s, minVal.y(), maxVal.y()); 608 float b = linearInterpolate(s, minVal.z(), maxVal.z()); 609 float a = linearInterpolate(s, minVal.w(), maxVal.w()); 610 611 access.setPixel(tcu::Vec4(r, g, b, a), x, 0); 612 } 613} 614 615static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal) 616{ 617 for (int y = 0; y < access.getHeight(); y++) 618 { 619 for (int x = 0; x < access.getWidth(); x++) 620 { 621 float s = ((float)x + 0.5f) / (float)access.getWidth(); 622 float t = ((float)y + 0.5f) / (float)access.getHeight(); 623 624 float r = linearInterpolate(( s + t) *0.5f, minVal.x(), maxVal.x()); 625 float g = linearInterpolate(( s + (1.0f-t))*0.5f, minVal.y(), maxVal.y()); 626 float b = linearInterpolate(((1.0f-s) + t) *0.5f, minVal.z(), maxVal.z()); 627 float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w()); 628 629 access.setPixel(tcu::Vec4(r, g, b, a), x, y); 630 } 631 } 632} 633 634static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal) 635{ 636 for (int z = 0; z < dst.getDepth(); z++) 637 { 638 for (int y = 0; y < dst.getHeight(); y++) 639 { 640 for (int x = 0; x < dst.getWidth(); x++) 641 { 642 float s = ((float)x + 0.5f) / (float)dst.getWidth(); 643 float t = ((float)y + 0.5f) / (float)dst.getHeight(); 644 float p = ((float)z + 0.5f) / (float)dst.getDepth(); 645 646 float r = linearInterpolate(s, minVal.x(), maxVal.x()); 647 float g = linearInterpolate(t, minVal.y(), maxVal.y()); 648 float b = linearInterpolate(p, minVal.z(), maxVal.z()); 649 float a = linearInterpolate(1.0f - (s+t+p)/3.0f, minVal.w(), maxVal.w()); 650 651 dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z); 652 } 653 } 654 } 655} 656 657void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal) 658{ 659 if (access.getHeight() == 1 && access.getDepth() == 1) 660 fillWithComponentGradients1D(access, minVal, maxVal); 661 else if (access.getDepth() == 1) 662 fillWithComponentGradients2D(access, minVal, maxVal); 663 else 664 fillWithComponentGradients3D(access, minVal, maxVal); 665} 666 667void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 668{ 669 for (int x = 0; x < access.getWidth(); x++) 670 { 671 int mx = (x / cellSize) % 2; 672 673 if (mx) 674 access.setPixel(colorB, x, 0); 675 else 676 access.setPixel(colorA, x, 0); 677 } 678} 679 680void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 681{ 682 for (int y = 0; y < access.getHeight(); y++) 683 { 684 for (int x = 0; x < access.getWidth(); x++) 685 { 686 int mx = (x / cellSize) % 2; 687 int my = (y / cellSize) % 2; 688 689 if (mx ^ my) 690 access.setPixel(colorB, x, y); 691 else 692 access.setPixel(colorA, x, y); 693 } 694 } 695} 696 697void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 698{ 699 for (int z = 0; z < access.getDepth(); z++) 700 { 701 for (int y = 0; y < access.getHeight(); y++) 702 { 703 for (int x = 0; x < access.getWidth(); x++) 704 { 705 int mx = (x / cellSize) % 2; 706 int my = (y / cellSize) % 2; 707 int mz = (z / cellSize) % 2; 708 709 if (mx ^ my ^ mz) 710 access.setPixel(colorB, x, y, z); 711 else 712 access.setPixel(colorA, x, y, z); 713 } 714 } 715 } 716} 717 718void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB) 719{ 720 if (access.getHeight() == 1 && access.getDepth() == 1) 721 fillWithGrid1D(access, cellSize, colorA, colorB); 722 else if (access.getDepth() == 1) 723 fillWithGrid2D(access, cellSize, colorA, colorB); 724 else 725 fillWithGrid3D(access, cellSize, colorA, colorB); 726} 727 728void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB) 729{ 730 for (int y = 0; y < access.getHeight(); y++) 731 { 732 for (int x = 0; x < access.getWidth(); x++) 733 { 734 float s = ((float)x + 0.5f) / (float)access.getWidth(); 735 float t = ((float)y + 0.5f) / (float)access.getHeight(); 736 737 float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s; 738 float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t; 739 740 float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f); 741 access.setPixel(linearInterpolate(p, colorA, colorB), x, y); 742 } 743 } 744} 745 746void fillWithRGBAQuads (const PixelBufferAccess& dst) 747{ 748 TCU_CHECK_INTERNAL(dst.getDepth() == 1); 749 int width = dst.getWidth(); 750 int height = dst.getHeight(); 751 int left = width/2; 752 int top = height/2; 753 754 clear(getSubregion(dst, 0, 0, 0, left, top, 1), Vec4(1.0f, 0.0f, 0.0f, 1.0f)); 755 clear(getSubregion(dst, left, 0, 0, width-left, top, 1), Vec4(0.0f, 1.0f, 0.0f, 1.0f)); 756 clear(getSubregion(dst, 0, top, 0, left, height-top, 1), Vec4(0.0f, 0.0f, 1.0f, 0.0f)); 757 clear(getSubregion(dst, left, top, 0, width-left, height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f)); 758} 759 760// \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators. 761void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed) 762{ 763 TCU_CHECK_INTERNAL(dst.getDepth() == 1); 764 std::vector<Vec2> points(numBalls); 765 de::Random rnd(seed); 766 767 for (int i = 0; i < numBalls; i++) 768 { 769 float x = rnd.getFloat(); 770 float y = rnd.getFloat(); 771 points[i] = (Vec2(x, y)); 772 } 773 774 for (int y = 0; y < dst.getHeight(); y++) 775 for (int x = 0; x < dst.getWidth(); x++) 776 { 777 Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight()); 778 779 float sum = 0.0f; 780 for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++) 781 { 782 Vec2 d = p - *i; 783 float f = 0.01f / (d.x()*d.x() + d.y()*d.y()); 784 785 sum += f; 786 } 787 788 dst.setPixel(Vec4(sum), x, y); 789 } 790} 791 792void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src) 793{ 794 DE_ASSERT(src.getSize() == dst.getSize()); 795 796 const int width = dst.getWidth(); 797 const int height = dst.getHeight(); 798 const int depth = dst.getDepth(); 799 800 const int srcPixelSize = src.getFormat().getPixelSize(); 801 const int dstPixelSize = dst.getFormat().getPixelSize(); 802 const int srcPixelPitch = src.getPixelPitch(); 803 const int dstPixelPitch = dst.getPixelPitch(); 804 const bool srcTightlyPacked = (srcPixelSize == srcPixelPitch); 805 const bool dstTightlyPacked = (dstPixelSize == dstPixelPitch); 806 807 if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked) 808 { 809 // Fast-path for matching formats. 810 for (int z = 0; z < depth; z++) 811 for (int y = 0; y < height; y++) 812 deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width); 813 } 814 else if (src.getFormat() == dst.getFormat()) 815 { 816 // Bit-exact copy for matching formats. 817 for (int z = 0; z < depth; z++) 818 for (int y = 0; y < height; y++) 819 for (int x = 0; x < width; x++) 820 deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize); 821 } 822 else 823 { 824 TextureChannelClass srcClass = getTextureChannelClass(src.getFormat().type); 825 TextureChannelClass dstClass = getTextureChannelClass(dst.getFormat().type); 826 bool srcIsInt = srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 827 bool dstIsInt = dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER; 828 829 if (srcIsInt && dstIsInt) 830 { 831 for (int z = 0; z < depth; z++) 832 for (int y = 0; y < height; y++) 833 for (int x = 0; x < width; x++) 834 dst.setPixel(src.getPixelInt(x, y, z), x, y, z); 835 } 836 else 837 { 838 for (int z = 0; z < depth; z++) 839 for (int y = 0; y < height; y++) 840 for (int x = 0; x < width; x++) 841 dst.setPixel(src.getPixel(x, y, z), x, y, z); 842 } 843 } 844} 845 846void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter) 847{ 848 DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR); 849 850 Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, 851 filter, filter, 0.0f, false); 852 853 float sX = (float)src.getWidth() / (float)dst.getWidth(); 854 float sY = (float)src.getHeight() / (float)dst.getHeight(); 855 float sZ = (float)src.getDepth() / (float)dst.getDepth(); 856 857 if (dst.getDepth() == 1 && src.getDepth() == 1) 858 { 859 for (int y = 0; y < dst.getHeight(); y++) 860 for (int x = 0; x < dst.getWidth(); x++) 861 dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y); 862 } 863 else 864 { 865 for (int z = 0; z < dst.getDepth(); z++) 866 for (int y = 0; y < dst.getHeight(); y++) 867 for (int x = 0; x < dst.getWidth(); x++) 868 dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z); 869 } 870} 871 872void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal) 873{ 874 const TextureFormat& format = access.getFormat(); 875 876 switch (format.type) 877 { 878 case TextureFormat::UNORM_INT8: 879 case TextureFormat::UNORM_INT16: 880 // Normalized unsigned formats. 881 minVal = Vec4(0.0f); 882 maxVal = Vec4(1.0f); 883 break; 884 885 case TextureFormat::SNORM_INT8: 886 case TextureFormat::SNORM_INT16: 887 // Normalized signed formats. 888 minVal = Vec4(-1.0f); 889 maxVal = Vec4(+1.0f); 890 break; 891 892 default: 893 // \note Samples every 4/8th pixel. 894 minVal = Vec4(std::numeric_limits<float>::max()); 895 maxVal = Vec4(std::numeric_limits<float>::min()); 896 897 for (int z = 0; z < access.getDepth(); z += 2) 898 { 899 for (int y = 0; y < access.getHeight(); y += 2) 900 { 901 for (int x = 0; x < access.getWidth(); x += 2) 902 { 903 Vec4 p = access.getPixel(x, y, z); 904 905 minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0])); 906 minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1])); 907 minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2])); 908 minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3])); 909 910 maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0])); 911 maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1])); 912 maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2])); 913 maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3])); 914 } 915 } 916 } 917 break; 918 } 919} 920 921void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias) 922{ 923 Vec4 minVal, maxVal; 924 estimatePixelValueRange(access, minVal, maxVal); 925 926 const float eps = 0.0001f; 927 928 for (int c = 0; c < 4; c++) 929 { 930 if (maxVal[c] - minVal[c] < eps) 931 { 932 scale[c] = (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]); 933 bias[c] = (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]); 934 } 935 else 936 { 937 scale[c] = 1.0f / (maxVal[c] - minVal[c]); 938 bias[c] = 0.0f - minVal[c]*scale[c]; 939 } 940 } 941} 942 943int getCubeArrayFaceIndex (CubeFace face) 944{ 945 DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST); 946 947 switch (face) 948 { 949 case CUBEFACE_POSITIVE_X: return 0; 950 case CUBEFACE_NEGATIVE_X: return 1; 951 case CUBEFACE_POSITIVE_Y: return 2; 952 case CUBEFACE_NEGATIVE_Y: return 3; 953 case CUBEFACE_POSITIVE_Z: return 4; 954 case CUBEFACE_NEGATIVE_Z: return 5; 955 956 default: 957 return -1; 958 } 959} 960 961deUint32 packRGB999E5 (const tcu::Vec4& color) 962{ 963 const int mBits = 9; 964 const int eBits = 5; 965 const int eBias = 15; 966 const int eMax = (1<<eBits)-1; 967 const float maxVal = (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits); 968 969 float rc = deFloatClamp(color[0], 0.0f, maxVal); 970 float gc = deFloatClamp(color[1], 0.0f, maxVal); 971 float bc = deFloatClamp(color[2], 0.0f, maxVal); 972 float maxc = de::max(rc, de::max(gc, bc)); 973 int expp = de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias; 974 float e = deFloatPow(2.0f, (float)(expp-eBias-mBits)); 975 int maxs = deFloorFloatToInt32(maxc / e + 0.5f); 976 977 deUint32 exps = maxs == (1<<mBits) ? expp+1 : expp; 978 deUint32 rs = (deUint32)deClamp32(deFloorFloatToInt32(rc / e + 0.5f), 0, (1<<9)-1); 979 deUint32 gs = (deUint32)deClamp32(deFloorFloatToInt32(gc / e + 0.5f), 0, (1<<9)-1); 980 deUint32 bs = (deUint32)deClamp32(deFloorFloatToInt32(bc / e + 0.5f), 0, (1<<9)-1); 981 982 DE_ASSERT((exps & ~((1<<5)-1)) == 0); 983 DE_ASSERT((rs & ~((1<<9)-1)) == 0); 984 DE_ASSERT((gs & ~((1<<9)-1)) == 0); 985 DE_ASSERT((bs & ~((1<<9)-1)) == 0); 986 987 return rs | (gs << 9) | (bs << 18) | (exps << 27); 988} 989 990} // tcu 991