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