Fix framework for R64 int images test
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / texture / vktSampleVerifierUtil.cpp
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
34 namespace vkt
35 {
36 namespace texture
37 {
38 namespace util
39 {
40
41 using namespace tcu;
42 using namespace vk;
43
44 deInt32 mod (const deInt32 a, const deInt32 n)
45 {
46         const deInt32 result = a % n;
47
48         return (result < 0) ? result + n : result;
49 }
50
51 deInt32 mirror (const deInt32 n)
52 {
53         if (n >= 0)
54         {
55                 return n;
56         }
57         else
58         {
59                 return -(1 + n);
60         }
61 }
62
63 UVec2 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
120 Vec2 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
138 float 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
150 void 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
194 void 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
209 void 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
247 void 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
268 Vec2 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
306 void 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
362 int 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
389 deInt32 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
425 namespace
426 {
427
428 // Cube map adjacent faces ordered clockwise from top
429 // \todo [2016-07-07 collinbaker] Verify these are correct
430 static 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
440 static 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
450 static 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
460 static const int edgeComponent[4] = {0, 1, 0, 1};
461
462 static const int edgeFactors[4][2] =
463 {
464         {0, 0},
465         {1, 0},
466         {0, 1},
467         {0, 0}
468 };
469
470 } // anonymous
471
472 void 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
518 void 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
606 namespace
607 {
608
609 deInt64 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
618 void 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
630 void 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
654 bool isPackedType (const TextureFormat::ChannelType type)
655 {
656         DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 42);
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
676 void getPackInfo (const TextureFormat texFormat,
677                                   IVec4& bitSizes,
678                                   IVec4& bitOffsets,
679                                   int& baseTypeBytes)
680 {
681         DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 42);
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
745 template <typename BaseType>
746 deUint64 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
757 deUint64 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
772 void convertNormalizedFormat (const void*                                               pixelPtr,
773                                                           TextureFormat                                         texFormat,
774                                                           const std::vector<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[compNdx], resultMin[compNdx], resultMax[compNdx]);
882
883                         // Special handling for components represented as 1 bit. In this case the only possible
884                         // converted values are 0.0 and 1.0, even after using roundOut() to account for the min
885                         // and max range of the converted value. For 1 bit values the min will always equal max.
886                         // To better reflect actual implementations sampling and filtering of converted 1 bit
887                         // values we need to modify the min/max range to include at least one ULP of the
888                         // internalFormat we're using. So if we're using 8 bit fractional precision for the
889                         // conversion instead a 1 bit value of "0" resulting in [0.0 .. 0.0] it will instead
890                         // be [0.0 .. 0.00390625], and a value of "1" resulting in [1.0 .. 1.0] will instead
891                         // be [0.99609375 .. 1.0]. Later when these values are used for calculating the
892                         // reference sampled and filtered values there will be a range that implementations
893                         // can fall between. Without this change, even after the reference sampling and filtering
894                         // calculations, there will be zero tolerance in the acceptable range since min==max
895                         // leaving zero room for rounding errors and arithmetic precision in the implementation.
896                         if (chanBits == 1)
897                         {
898                                 if (resultMin[compNdx] == 1.0f)
899                                         resultMin[compNdx] -= float(internalFormat[compNdx].ulp(1.0));
900                                 if (resultMax[compNdx] == 0.0f)
901                                         resultMax[compNdx] += float(internalFormat[compNdx].ulp(0.0));
902                         }
903                 }
904         }
905 }
906
907 void convertFloatFormat (const void*                                            pixelPtr,
908                                                  TextureFormat                                          texFormat,
909                                                  const std::vector<FloatFormat>&        internalFormat,
910                                                  Vec4&                                                          resultMin,
911                                                  Vec4&                                                          resultMax)
912 {
913         DE_ASSERT(getTextureChannelClass(texFormat.type) == TEXTURECHANNELCLASS_FLOATING_POINT);
914
915         const TextureSwizzle readSwizzle = getChannelReadSwizzle(texFormat.order);
916
917         for (int compNdx = 0; compNdx < 4; ++compNdx)
918         {
919                 const TextureSwizzle::Channel chan = readSwizzle.components[compNdx];
920
921                 if (chan == TextureSwizzle::CHANNEL_ZERO)
922                 {
923                         resultMin[compNdx] = 0.0f;
924                         resultMax[compNdx] = 0.0f;
925                 }
926                 else if (chan == TextureSwizzle::CHANNEL_ONE)
927                 {
928                         resultMin[compNdx] = 1.0f;
929                         resultMax[compNdx] = 1.0f;
930                 }
931                 else if (texFormat.type == TextureFormat::FLOAT)
932                 {
933                         resultMin[compNdx] = resultMax[compNdx] = *((const float*)pixelPtr + chan);
934                 }
935                 else if (texFormat.type == TextureFormat::HALF_FLOAT)
936                 {
937                         convertFP16((const deUint16*) pixelPtr + chan, internalFormat[compNdx], resultMin[compNdx], resultMax[compNdx]);
938                 }
939                 else
940                 {
941                         DE_FATAL("Unsupported floating point format");
942                 }
943         }
944 }
945
946 } // anonymous
947
948 void convertFormat (const void*                                         pixelPtr,
949                                         TextureFormat                                   texFormat,
950                                         const std::vector<FloatFormat>& internalFormat,
951                                         Vec4&                                                   resultMin,
952                                         Vec4&                                                   resultMax)
953 {
954         const TextureChannelClass       chanClass        = getTextureChannelClass(texFormat.type);
955
956         // \todo [2016-08-01 collinbaker] Handle float and shared exponent formats
957         if (chanClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || chanClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
958         {
959                 convertNormalizedFormat(pixelPtr, texFormat, internalFormat, resultMin, resultMax);
960         }
961         else if (chanClass == TEXTURECHANNELCLASS_FLOATING_POINT)
962         {
963                 convertFloatFormat(pixelPtr, texFormat, internalFormat, resultMin, resultMax);
964         }
965         else
966         {
967                 DE_FATAL("Unimplemented");
968         }
969 }
970
971 } // util
972 } // texture
973 } // vkt