1/*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 Google Inc. 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 GPU image sample verification 22 *//*--------------------------------------------------------------------*/ 23 24#include "vktSampleVerifierUtil.hpp" 25 26#include "deMath.h" 27#include "tcuDefs.hpp" 28#include "tcuFloat.hpp" 29#include "tcuFloatFormat.hpp" 30#include "tcuInterval.hpp" 31#include "tcuTexture.hpp" 32#include "tcuTextureUtil.hpp" 33 34namespace vkt 35{ 36namespace texture 37{ 38namespace util 39{ 40 41using namespace tcu; 42using namespace vk; 43 44deInt32 mod (const deInt32 a, const deInt32 n) 45{ 46 const deInt32 result = a % n; 47 48 return (result < 0) ? result + n : result; 49} 50 51deInt32 mirror (const deInt32 n) 52{ 53 if (n >= 0) 54 { 55 return n; 56 } 57 else 58 { 59 return -(1 + n); 60 } 61} 62 63UVec2 calcLevelBounds (const Vec2& lodBounds, 64 const int levelCount, 65 VkSamplerMipmapMode mipmapFilter) 66{ 67 DE_ASSERT(lodBounds[0] <= lodBounds[1]); 68 DE_ASSERT(levelCount > 0); 69 70 const float q = (float) (levelCount - 1); 71 72 UVec2 levelBounds; 73 74 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_NEAREST) 75 { 76 if (lodBounds[0] <= 0.5f) 77 { 78 levelBounds[0] = 0; 79 } 80 else if (lodBounds[0] < q + 0.5f) 81 { 82 levelBounds[0] = deCeilFloatToInt32(lodBounds[0] + 0.5f) - 1; 83 } 84 else 85 { 86 levelBounds[0] = deRoundFloatToInt32(q); 87 } 88 89 if (lodBounds[1] < 0.5f) 90 { 91 levelBounds[1] = 0; 92 } 93 else if (lodBounds[1] < q + 0.5f) 94 { 95 levelBounds[1] = deFloorFloatToInt32(lodBounds[1] + 0.5f); 96 } 97 else 98 { 99 levelBounds[1] = deRoundFloatToInt32(q); 100 } 101 } 102 else 103 { 104 for (int ndx = 0; ndx < 2; ++ndx) 105 { 106 if (lodBounds[ndx] >= q) 107 { 108 levelBounds[ndx] = deRoundFloatToInt32(q); 109 } 110 else 111 { 112 levelBounds[ndx] = lodBounds[ndx] < 0.0f ? 0 : deFloorFloatToInt32(lodBounds[ndx]); 113 } 114 } 115 } 116 117 return levelBounds; 118} 119 120Vec2 calcLevelLodBounds (const Vec2& lodBounds, int level) 121{ 122 Vec2 levelLodBounds; 123 124 if (lodBounds[0] <= 0.0f) 125 { 126 levelLodBounds[0] = lodBounds[0]; 127 } 128 else 129 { 130 levelLodBounds[0] = de::max(lodBounds[0], (float) level); 131 } 132 133 levelLodBounds[1] = de::min(lodBounds[1], (float) level + 1.0f); 134 135 return levelLodBounds; 136} 137 138float addUlp (float num, deInt32 ulp) 139{ 140 // Note: adding positive ulp always moves float away from zero 141 142 const tcu::Float32 f(num); 143 144 DE_ASSERT(!f.isNaN() && !f.isInf()); 145 DE_ASSERT(num > FLT_MIN * (float) ulp || num < FLT_MIN * (float) ulp); 146 147 return tcu::Float32(f.bits() + ulp).asFloat(); 148} 149 150void wrapTexelGridCoordLinear (IVec3& baseTexel, 151 IVec3& texelGridOffset, 152 const int coordBits, 153 const ImgDim dim) 154{ 155 const int subdivisions = 1 << coordBits; 156 157 int numComp; 158 159 switch (dim) 160 { 161 case IMG_DIM_1D: 162 numComp = 1; 163 break; 164 165 case IMG_DIM_2D: 166 numComp = 2; 167 break; 168 169 case IMG_DIM_CUBE: 170 numComp = 2; 171 break; 172 173 case IMG_DIM_3D: 174 numComp = 3; 175 break; 176 177 default: 178 numComp = 0; 179 break; 180 } 181 182 for (int compNdx = 0; compNdx < numComp; ++compNdx) 183 { 184 texelGridOffset[compNdx] -= subdivisions / (int) 2; 185 186 if (texelGridOffset[compNdx] < 0) 187 { 188 baseTexel [compNdx] -= 1; 189 texelGridOffset[compNdx] += (deInt32) subdivisions; 190 } 191 } 192} 193 194void calcTexelBaseOffset (const IVec3& gridCoord, 195 const int coordBits, 196 IVec3& baseTexel, 197 IVec3& texelGridOffset) 198{ 199 const int subdivisions = (int) 1 << coordBits; 200 201 for (int compNdx = 0; compNdx < 3; ++compNdx) 202 { 203 // \todo [2016-07-22 collinbaker] Do floor division to properly handle negative coords 204 baseTexel[compNdx] = gridCoord[compNdx] / (deInt32) subdivisions; 205 texelGridOffset[compNdx] = gridCoord[compNdx] % (deInt32) subdivisions; 206 } 207} 208 209void calcTexelGridCoordRange (const Vec3& unnormalizedCoordMin, 210 const Vec3& unnormalizedCoordMax, 211 const int coordBits, 212 IVec3& gridCoordMin, 213 IVec3& gridCoordMax) 214{ 215 const int subdivisions = 1 << coordBits; 216 217 for (int compNdx = 0; compNdx < 3; ++compNdx) 218 { 219 const float comp[2] = {unnormalizedCoordMin[compNdx], 220 unnormalizedCoordMax[compNdx]}; 221 222 float fracPart[2]; 223 double intPart[2]; 224 225 for (int ndx = 0; ndx < 2; ++ndx) 226 { 227 fracPart[ndx] = (float) deModf(comp[ndx], &intPart[ndx]); 228 229 if (comp[ndx] < 0.0f) 230 { 231 intPart [ndx] -= 1.0; 232 fracPart[ndx] += 1.0f; 233 } 234 } 235 236 const deInt32 nearestTexelGridOffsetMin = (deInt32) deFloor(intPart[0]); 237 const deInt32 nearestTexelGridOffsetMax = (deInt32) deFloor(intPart[1]); 238 239 const deInt32 subTexelGridCoordMin = de::max((deInt32) deFloor(fracPart[0] * (float) subdivisions), (deInt32) 0); 240 const deInt32 subTexelGridCoordMax = de::min((deInt32) deCeil (fracPart[1] * (float) subdivisions), (deInt32) (subdivisions - 1)); 241 242 gridCoordMin[compNdx] = nearestTexelGridOffsetMin * (deInt32) subdivisions + subTexelGridCoordMin; 243 gridCoordMax[compNdx] = nearestTexelGridOffsetMax * (deInt32) subdivisions + subTexelGridCoordMax; 244 } 245} 246 247void calcUnnormalizedCoordRange (const Vec4& coord, 248 const IVec3& levelSize, 249 const FloatFormat& internalFormat, 250 Vec3& unnormalizedCoordMin, 251 Vec3& unnormalizedCoordMax) 252{ 253 for (int compNdx = 0; compNdx < 3; ++compNdx) 254 { 255 const int size = levelSize[compNdx]; 256 257 Interval coordInterval = Interval(coord[compNdx]); 258 coordInterval = internalFormat.roundOut(coordInterval, false); 259 260 Interval unnormalizedCoordInterval = coordInterval * Interval((double) size); 261 unnormalizedCoordInterval = internalFormat.roundOut(unnormalizedCoordInterval, false); 262 263 unnormalizedCoordMin[compNdx] = (float)unnormalizedCoordInterval.lo(); 264 unnormalizedCoordMax[compNdx] = (float)unnormalizedCoordInterval.hi(); 265 } 266} 267 268Vec2 calcLodBounds (const Vec3& dPdx, 269 const Vec3& dPdy, 270 const IVec3 size, 271 const float lodBias, 272 const float lodMin, 273 const float lodMax) 274{ 275 Vec2 lodBounds; 276 277 const Vec3 mx = abs(dPdx) * size.asFloat(); 278 const Vec3 my = abs(dPdy) * size.asFloat(); 279 280 Vec2 scaleXBounds; 281 Vec2 scaleYBounds; 282 283 scaleXBounds[0] = de::max(de::abs(mx[0]), de::max(de::abs(mx[1]), de::abs(mx[2]))); 284 scaleYBounds[0] = de::max(de::abs(my[0]), de::max(de::abs(my[1]), de::abs(my[2]))); 285 286 scaleXBounds[1] = de::abs(mx[0]) + de::abs(mx[1]) + de::abs(mx[2]); 287 scaleYBounds[1] = de::abs(my[0]) + de::abs(my[1]) + de::abs(my[2]); 288 289 Vec2 scaleMaxBounds; 290 291 for (int compNdx = 0; compNdx < 2; ++compNdx) 292 { 293 scaleMaxBounds[compNdx] = de::max(scaleXBounds[compNdx], scaleYBounds[compNdx]); 294 } 295 296 for (int ndx = 0; ndx < 2; ++ndx) 297 { 298 lodBounds[ndx] = deFloatLog2(scaleMaxBounds[ndx]); 299 lodBounds[ndx] += lodBias; 300 lodBounds[ndx] = de::clamp(lodBounds[ndx], lodMin, lodMax); 301 } 302 303 return lodBounds; 304} 305 306void calcCubemapFaceCoords (const Vec3& r, 307 const Vec3& drdx, 308 const Vec3& drdy, 309 const int faceNdx, 310 Vec2& coordFace, 311 Vec2& dPdxFace, 312 Vec2& dPdyFace) 313{ 314 DE_ASSERT(faceNdx >= 0 && faceNdx < 6); 315 316 static const int compMap[6][3] = 317 { 318 {2, 1, 0}, 319 {2, 1, 0}, 320 {0, 2, 1}, 321 {0, 2, 1}, 322 {0, 1, 2}, 323 {0, 1, 2} 324 }; 325 326 static const int signMap[6][3] = 327 { 328 {-1, -1, +1}, 329 {+1, -1, -1}, 330 {+1, +1, +1}, 331 {+1, -1, -1}, 332 {+1, -1, +1}, 333 {-1, -1, -1} 334 }; 335 336 Vec3 coordC; 337 Vec3 dPcdx; 338 Vec3 dPcdy; 339 340 for (int compNdx = 0; compNdx < 3; ++compNdx) 341 { 342 const int mappedComp = compMap[faceNdx][compNdx]; 343 const int mappedSign = signMap[faceNdx][compNdx]; 344 345 coordC[compNdx] = r [mappedComp] * (float)mappedSign; 346 dPcdx [compNdx] = drdx[mappedComp] * (float)mappedSign; 347 dPcdy [compNdx] = drdy[mappedComp] * (float)mappedSign; 348 } 349 350 DE_ASSERT(coordC[2] != 0.0f); 351 coordC[2] = de::abs(coordC[2]); 352 353 for (int compNdx = 0; compNdx < 2; ++compNdx) 354 { 355 coordFace[compNdx] = 0.5f * coordC[compNdx] / de::abs(coordC[2]) + 0.5f; 356 357 dPdxFace [compNdx] = 0.5f * (de::abs(coordC[2]) * dPcdx[compNdx] - coordC[compNdx] * dPcdx[2]) / (coordC[2] * coordC[2]); 358 dPdyFace [compNdx] = 0.5f * (de::abs(coordC[2]) * dPcdy[compNdx] - coordC[compNdx] * dPcdy[2]) / (coordC[2] * coordC[2]); 359 } 360} 361 362int calcCandidateCubemapFaces (const Vec3& r) 363{ 364 deUint8 faceBitmap = 0; 365 float rMax = de::abs(r[0]); 366 367 for (int compNdx = 1; compNdx < 3; ++compNdx) 368 { 369 rMax = de::max(rMax, de::abs(r[compNdx])); 370 } 371 372 for (int compNdx = 0; compNdx < 3; ++compNdx) 373 { 374 if (de::abs(r[compNdx]) == rMax) 375 { 376 const int faceNdx = 2 * compNdx + (r[compNdx] < 0.0f ? 1 : 0); 377 378 DE_ASSERT(faceNdx < 6); 379 380 faceBitmap = (deUint8)(faceBitmap | (deUint8) (1U << faceNdx)); 381 } 382 } 383 384 DE_ASSERT(faceBitmap != 0U); 385 386 return faceBitmap; 387} 388 389deInt32 wrapTexelCoord (const deInt32 coord, 390 const int size, 391 const VkSamplerAddressMode wrap) 392{ 393 deInt32 wrappedCoord = 0; 394 395 switch (wrap) 396 { 397 case VK_SAMPLER_ADDRESS_MODE_REPEAT: 398 wrappedCoord = mod(coord, size); 399 break; 400 401 case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: 402 wrappedCoord = (size - 1) - mirror(mod(coord, 2 * size) - size); 403 break; 404 405 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: 406 wrappedCoord = de::clamp(coord, 0, (deInt32) size - 1); 407 break; 408 409 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: 410 wrappedCoord = de::clamp(coord, -1, (deInt32) size); 411 break; 412 413 case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: 414 wrappedCoord = de::clamp(mirror(coord), 0, (deInt32) size - 1); 415 break; 416 417 default: 418 DE_FATAL("Invalid VkSamplerAddressMode"); 419 break; 420 } 421 422 return wrappedCoord; 423} 424 425namespace 426{ 427 428// Cube map adjacent faces ordered clockwise from top 429// \todo [2016-07-07 collinbaker] Verify these are correct 430static const int adjacentFaces[6][4] = 431{ 432 {3, 5, 2, 4}, 433 {3, 4, 2, 5}, 434 {4, 0, 5, 1}, 435 {5, 0, 4, 1}, 436 {3, 0, 2, 1}, 437 {3, 1, 2, 0} 438}; 439 440static const int adjacentEdges[6][4] = 441{ 442 {1, 3, 1, 1}, 443 {3, 3, 3, 1}, 444 {2, 2, 2, 2}, 445 {0, 0, 0, 0}, 446 {2, 3, 0, 1}, 447 {0, 3, 2, 1} 448}; 449 450static const int adjacentEdgeDirs[6][4] = 451{ 452 {-1, +1, +1, +1}, 453 {+1, +1, -1, +1}, 454 {+1, +1, -1, -1}, 455 {-1, -1, +1, +1}, 456 {+1, +1, +1, +1}, 457 {-1, +1, -1, +1} 458}; 459 460static const int edgeComponent[4] = {0, 1, 0, 1}; 461 462static const int edgeFactors[4][2] = 463{ 464 {0, 0}, 465 {1, 0}, 466 {0, 1}, 467 {0, 0} 468}; 469 470} // anonymous 471 472void wrapCubemapEdge (const IVec2& coord, 473 const IVec2& size, 474 const int faceNdx, 475 IVec2& newCoord, 476 int& newFaceNdx) 477{ 478 int edgeNdx = -1; 479 480 if (coord[1] < 0) 481 { 482 edgeNdx = 0; 483 } 484 else if (coord[0] > 0) 485 { 486 edgeNdx = 1; 487 } 488 else if (coord[1] > 0) 489 { 490 edgeNdx = 2; 491 } 492 else 493 { 494 edgeNdx = 3; 495 } 496 497 const int adjacentEdgeNdx = adjacentEdges[faceNdx][edgeNdx]; 498 const IVec2 edgeFactor = IVec2(edgeFactors[adjacentEdgeNdx][0], 499 edgeFactors[adjacentEdgeNdx][1]); 500 const IVec2 edgeOffset = edgeFactor * (size - IVec2(1)); 501 502 if (adjacentEdgeDirs[faceNdx][edgeNdx] > 0) 503 { 504 newCoord[edgeComponent[adjacentEdgeNdx]] = coord[edgeComponent[edgeNdx]]; 505 } 506 else 507 { 508 newCoord[edgeComponent[adjacentEdgeNdx]] = 509 size[edgeComponent[edgeNdx]] - coord[edgeComponent[edgeNdx]] - 1; 510 } 511 512 newCoord[1 - edgeComponent[adjacentEdgeNdx]] = 0; 513 newCoord += edgeOffset; 514 515 newFaceNdx = adjacentFaces[faceNdx][edgeNdx]; 516} 517 518void wrapCubemapCorner (const IVec2& coord, 519 const IVec2& size, 520 const int faceNdx, 521 int& adjacentFace1, 522 int& adjacentFace2, 523 IVec2& cornerCoord0, 524 IVec2& cornerCoord1, 525 IVec2& cornerCoord2) 526{ 527 int cornerNdx = -1; 528 529 if (coord[0] < 0 && coord[1] < 0) 530 { 531 cornerNdx = 0; 532 } 533 else if (coord[0] > 0 && coord[1] < 0) 534 { 535 cornerNdx = 1; 536 } 537 else if (coord[0] > 0 && coord[1] > 0) 538 { 539 cornerNdx = 2; 540 } 541 else 542 { 543 cornerNdx = 3; 544 } 545 546 const int cornerEdges[2] = {cornerNdx, (int) ((cornerNdx + 3) % 4)}; 547 548 int faceCorners[3] = {cornerNdx, 0, 0}; 549 550 for (int edgeNdx = 0; edgeNdx < 2; ++edgeNdx) 551 { 552 const int faceEdge = adjacentEdges[faceNdx][cornerEdges[edgeNdx]]; 553 554 bool isFlipped = (adjacentEdgeDirs[faceNdx][cornerEdges[edgeNdx]] == -1); 555 556 if ((cornerEdges[edgeNdx] > 1) != (faceEdge > 1)) 557 { 558 isFlipped = !isFlipped; 559 } 560 561 if (isFlipped) 562 { 563 faceCorners[edgeNdx + 1] = (faceEdge + 1) % 4; 564 } 565 else 566 { 567 faceCorners[edgeNdx + 1] = faceEdge; 568 } 569 } 570 571 adjacentFace1 = adjacentFaces[faceNdx][cornerEdges[0]]; 572 adjacentFace2 = adjacentFaces[faceNdx][cornerEdges[1]]; 573 574 IVec2* cornerCoords[3] = {&cornerCoord0, &cornerCoord1, &cornerCoord2}; 575 576 for (int ndx = 0; ndx < 3; ++ndx) 577 { 578 IVec2 cornerFactor; 579 580 switch (faceCorners[faceNdx]) 581 { 582 case 0: 583 cornerFactor = IVec2(0, 0); 584 break; 585 586 case 1: 587 cornerFactor = IVec2(1, 0); 588 break; 589 590 case 2: 591 cornerFactor = IVec2(1, 1); 592 break; 593 594 case 3: 595 cornerFactor = IVec2(0, 1); 596 break; 597 598 default: 599 break; 600 } 601 602 *cornerCoords[ndx] = cornerFactor * (size - IVec2(1)); 603 } 604} 605 606namespace 607{ 608 609deInt64 signExtend (deUint64 src, int bits) 610{ 611 const deUint64 signBit = 1ull << (bits-1); 612 613 src |= ~((src & signBit) - 1); 614 615 return (deInt64) src; 616} 617 618void convertFP16 (const void* fp16Ptr, 619 FloatFormat internalFormat, 620 float& resultMin, 621 float& resultMax) 622{ 623 const Float16 fp16(*(const deUint16*) fp16Ptr); 624 const Interval fpInterval = internalFormat.roundOut(Interval(fp16.asDouble()), false); 625 626 resultMin = (float) fpInterval.lo(); 627 resultMax = (float) fpInterval.hi(); 628} 629 630void convertNormalizedInt (deInt64 num, 631 int numBits, 632 bool isSigned, 633 FloatFormat internalFormat, 634 float& resultMin, 635 float& resultMax) 636{ 637 DE_ASSERT(numBits > 0); 638 639 const double c = (double) num; 640 deUint64 exp = numBits; 641 642 if (isSigned) 643 --exp; 644 645 const double div = (double) (((deUint64) 1 << exp) - 1); 646 647 Interval resultInterval(de::max(c / div, -1.0)); 648 resultInterval = internalFormat.roundOut(resultInterval, false); 649 650 resultMin = (float) resultInterval.lo(); 651 resultMax = (float) resultInterval.hi(); 652} 653 654bool isPackedType (const TextureFormat::ChannelType type) 655{ 656 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40); 657 658 switch (type) 659 { 660 case TextureFormat::UNORM_BYTE_44: 661 case TextureFormat::UNORM_SHORT_565: 662 case TextureFormat::UNORM_SHORT_555: 663 case TextureFormat::UNORM_SHORT_4444: 664 case TextureFormat::UNORM_SHORT_5551: 665 case TextureFormat::UNORM_SHORT_1555: 666 case TextureFormat::UNORM_INT_101010: 667 case TextureFormat::SNORM_INT_1010102_REV: 668 case TextureFormat::UNORM_INT_1010102_REV: 669 return true; 670 671 default: 672 return false; 673 } 674} 675 676void getPackInfo (const TextureFormat texFormat, 677 IVec4& bitSizes, 678 IVec4& bitOffsets, 679 int& baseTypeBytes) 680{ 681 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40); 682 683 switch (texFormat.type) 684 { 685 case TextureFormat::UNORM_BYTE_44: 686 bitSizes = IVec4(4, 4, 0, 0); 687 bitOffsets = IVec4(0, 4, 0, 0); 688 baseTypeBytes = 1; 689 break; 690 691 case TextureFormat::UNORM_SHORT_565: 692 bitSizes = IVec4(5, 6, 5, 0); 693 bitOffsets = IVec4(0, 5, 11, 0); 694 baseTypeBytes = 2; 695 break; 696 697 case TextureFormat::UNORM_SHORT_555: 698 bitSizes = IVec4(5, 5, 5, 0); 699 bitOffsets = IVec4(0, 5, 10, 0); 700 baseTypeBytes = 2; 701 break; 702 703 case TextureFormat::UNORM_SHORT_4444: 704 bitSizes = IVec4(4, 4, 4, 4); 705 bitOffsets = IVec4(0, 4, 8, 12); 706 baseTypeBytes = 2; 707 break; 708 709 case TextureFormat::UNORM_SHORT_5551: 710 bitSizes = IVec4(5, 5, 5, 1); 711 bitOffsets = IVec4(0, 5, 10, 15); 712 baseTypeBytes = 2; 713 break; 714 715 case TextureFormat::UNORM_SHORT_1555: 716 bitSizes = IVec4(1, 5, 5, 5); 717 bitOffsets = IVec4(0, 1, 6, 11); 718 baseTypeBytes = 2; 719 break; 720 721 case TextureFormat::UNORM_INT_101010: 722 bitSizes = IVec4(10, 10, 10, 0); 723 bitOffsets = IVec4(0, 10, 20, 0); 724 baseTypeBytes = 4; 725 break; 726 727 case TextureFormat::SNORM_INT_1010102_REV: 728 bitSizes = IVec4(2, 10, 10, 10); 729 bitOffsets = IVec4(0, 2, 12, 22); 730 baseTypeBytes = 4; 731 break; 732 733 case TextureFormat::UNORM_INT_1010102_REV: 734 bitSizes = IVec4(2, 10, 10, 10); 735 bitOffsets = IVec4(0, 2, 12, 22); 736 baseTypeBytes = 4; 737 break; 738 739 default: 740 DE_FATAL("Invalid texture channel type"); 741 return; 742 } 743} 744 745template <typename BaseType> 746deUint64 unpackBits (const BaseType pack, 747 const int bitOffset, 748 const int numBits) 749{ 750 DE_ASSERT(bitOffset + numBits <= 8 * (int) sizeof(BaseType)); 751 752 const BaseType mask = (BaseType) (((BaseType) 1 << (BaseType) numBits) - (BaseType) 1); 753 754 return mask & (pack >> (BaseType) (8 * (int) sizeof(BaseType) - bitOffset - numBits)); 755} 756 757deUint64 readChannel (const void* ptr, 758 const int byteOffset, 759 const int numBytes) 760{ 761 const deUint8* cPtr = (const deUint8*) ptr + byteOffset; 762 deUint64 result = 0; 763 764 for (int byteNdx = 0; byteNdx < numBytes; ++byteNdx) 765 { 766 result = (result << 8U) | (deUint64) (cPtr[numBytes - byteNdx - 1]); 767 } 768 769 return result; 770} 771 772void convertNormalizedFormat (const void* pixelPtr, 773 TextureFormat texFormat, 774 FloatFormat internalFormat, 775 Vec4& resultMin, 776 Vec4& resultMax) 777{ 778 TextureSwizzle readSwizzle = getChannelReadSwizzle(texFormat.order); 779 const TextureChannelClass chanClass = getTextureChannelClass(texFormat.type); 780 781 DE_ASSERT(getTextureChannelClass(texFormat.type) < 2); 782 783 // Information for non-packed types 784 int chanSize = -1; 785 786 // Information for packed types 787 IVec4 bitOffsets; 788 IVec4 bitSizes; 789 int baseTypeBytes = -1; 790 791 const bool isPacked = isPackedType(texFormat.type); 792 793 if (isPacked) 794 { 795 getPackInfo(texFormat, bitSizes, bitOffsets, baseTypeBytes); 796 797 // Kludge to work around deficiency in framework 798 799 if (texFormat.type == TextureFormat::UNORM_INT_1010102_REV || 800 texFormat.type == TextureFormat::SNORM_INT_1010102_REV) 801 { 802 for (int ndx = 0; ndx < 2; ++ndx) 803 { 804 std::swap(readSwizzle.components[ndx], readSwizzle.components[3 - ndx]); 805 } 806 } 807 808 DE_ASSERT(baseTypeBytes == 1 || baseTypeBytes == 2 || baseTypeBytes == 4); 809 } 810 else 811 { 812 chanSize = getChannelSize(texFormat.type); 813 } 814 815 const bool isSigned = (chanClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT); 816 const bool isSrgb = isSRGB(texFormat); 817 818 // \todo [2016-08-01 collinbaker] Handle sRGB with correct rounding 819 DE_ASSERT(!isSrgb); 820 DE_UNREF(isSrgb); 821 822 for (int compNdx = 0; compNdx < 4; ++compNdx) 823 { 824 const TextureSwizzle::Channel chan = readSwizzle.components[compNdx]; 825 826 if (chan == TextureSwizzle::CHANNEL_ZERO) 827 { 828 resultMin[compNdx] = 0.0f; 829 resultMax[compNdx] = 0.0f; 830 } 831 else if (chan == TextureSwizzle::CHANNEL_ONE) 832 { 833 resultMin[compNdx] = 1.0f; 834 resultMax[compNdx] = 1.0f; 835 } 836 else 837 { 838 deUint64 chanUVal = 0; 839 int chanBits = 0; 840 841 if (isPacked) 842 { 843 deUint64 pack = readChannel(pixelPtr, 0, baseTypeBytes); 844 chanBits = bitSizes[chan]; 845 846 switch (baseTypeBytes) 847 { 848 case 1: 849 chanUVal = unpackBits<deUint8>((deUint8)pack, bitOffsets[chan], bitSizes[chan]); 850 break; 851 852 case 2: 853 chanUVal = unpackBits<deUint16>((deUint16)pack, bitOffsets[chan], bitSizes[chan]); 854 break; 855 856 case 4: 857 chanUVal = unpackBits<deUint32>((deUint32)pack, bitOffsets[chan], bitSizes[chan]); 858 break; 859 860 default: 861 break; 862 } 863 } 864 else 865 { 866 chanUVal = readChannel(pixelPtr, chan * chanSize, chanSize); 867 chanBits = 8 * chanSize; 868 } 869 870 deInt64 chanVal = 0; 871 872 if (isSigned) 873 { 874 chanVal = signExtend(chanUVal, chanBits); 875 } 876 else 877 { 878 chanVal = (deInt64) chanUVal; 879 } 880 881 convertNormalizedInt(chanVal, chanBits, isSigned, internalFormat, resultMin[compNdx], resultMax[compNdx]); 882 } 883 } 884} 885 886void convertFloatFormat (const void* pixelPtr, 887 TextureFormat texFormat, 888 FloatFormat internalFormat, 889 Vec4& resultMin, 890 Vec4& resultMax) 891{ 892 DE_ASSERT(getTextureChannelClass(texFormat.type) == TEXTURECHANNELCLASS_FLOATING_POINT); 893 894 const TextureSwizzle readSwizzle = getChannelReadSwizzle(texFormat.order); 895 896 for (int compNdx = 0; compNdx < 4; ++compNdx) 897 { 898 const TextureSwizzle::Channel chan = readSwizzle.components[compNdx]; 899 900 if (chan == TextureSwizzle::CHANNEL_ZERO) 901 { 902 resultMin[compNdx] = 0.0f; 903 resultMax[compNdx] = 0.0f; 904 } 905 else if (chan == TextureSwizzle::CHANNEL_ONE) 906 { 907 resultMin[compNdx] = 1.0f; 908 resultMax[compNdx] = 1.0f; 909 } 910 else if (texFormat.type == TextureFormat::FLOAT) 911 { 912 resultMin[compNdx] = resultMax[compNdx] = *((const float*)pixelPtr + chan); 913 } 914 else if (texFormat.type == TextureFormat::HALF_FLOAT) 915 { 916 convertFP16((const deUint16*) pixelPtr + chan, internalFormat, resultMin[compNdx], resultMax[compNdx]); 917 } 918 else 919 { 920 DE_FATAL("Unsupported floating point format"); 921 } 922 } 923} 924 925} // anonymous 926 927void convertFormat (const void* pixelPtr, 928 TextureFormat texFormat, 929 FloatFormat internalFormat, 930 Vec4& resultMin, 931 Vec4& resultMax) 932{ 933 const TextureChannelClass chanClass = getTextureChannelClass(texFormat.type); 934 935 // \todo [2016-08-01 collinbaker] Handle float and shared exponent formats 936 if (chanClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || chanClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) 937 { 938 convertNormalizedFormat(pixelPtr, texFormat, internalFormat, resultMin, resultMax); 939 } 940 else if (chanClass == TEXTURECHANNELCLASS_FLOATING_POINT) 941 { 942 convertFloatFormat(pixelPtr, texFormat, internalFormat, resultMin, resultMax); 943 } 944 else 945 { 946 DE_FATAL("Unimplemented"); 947 } 948} 949 950} // util 951} // texture 952} // vkt 953