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