Improvements to sample verification code
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / texture_filtering / vktSampleVerifier.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 "vktSampleVerifier.hpp"
25 #include "vktSampleVerifierUtil.hpp"
26
27 #include "deMath.h"
28 #include "tcuFloat.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "vkImageUtil.hpp"
31
32 #include <fstream>
33 #include <sstream>
34
35 namespace vkt
36 {
37 namespace texture_filtering
38 {
39
40 using namespace vk;
41 using namespace tcu;
42 using namespace util;
43
44 namespace
45 {
46
47 int calcUnnormalizedDim (const ImgDim dim)
48 {
49         if (dim == IMG_DIM_1D)
50         {
51             return 1;
52         }
53         else if (dim == IMG_DIM_2D || dim == IMG_DIM_CUBE)
54         {
55             return 2;
56         }
57         else
58         {
59             return 3;
60         }
61 }
62
63 } // anonymous
64
65 SampleVerifier::SampleVerifier (const ImageViewParameters&                                              imParams,
66                                                                 const SamplerParameters&                                                samplerParams,
67                                                                 const SampleLookupSettings&                                             sampleLookupSettings,
68                                                                 int                                                                                             coordBits,
69                                                                 int                                                                                             mipmapBits,
70                                                                 const std::vector<tcu::ConstPixelBufferAccess>& pba)
71 // \todo [2016-07-29 collinbaker] Get rid of magic numbers
72         : m_internalFormat                      (-14, 15, 10, true) // fp16 format
73         , m_imParams                            (imParams)
74         , m_samplerParams                       (samplerParams)
75         , m_sampleLookupSettings        (sampleLookupSettings)
76         , m_coordBits                           (coordBits)
77         , m_mipmapBits                          (mipmapBits)
78         , m_unnormalizedDim                     (calcUnnormalizedDim(imParams.dim))
79         , m_pba                                         (pba)
80 {
81
82 }
83
84 bool SampleVerifier::coordOutOfRange (const IVec3& coord, int compNdx, int level) const
85 {
86         DE_ASSERT(compNdx >= 0 && compNdx < 3);
87
88         return coord[compNdx] < 0 || coord[compNdx] >= m_pba[level].getSize()[compNdx];
89 }
90
91 void SampleVerifier::fetchTexelWrapped (const IVec3&    coord,
92                                                                                 int                             layer,
93                                                                                 int                             level,
94                                                                                 Vec4&                   resultMin,
95                                                                                 Vec4&                   resultMax) const
96 {
97     const void* pixelPtr = DE_NULL;
98
99         if (m_imParams.dim == IMG_DIM_1D)
100         {
101             pixelPtr = m_pba[level].getPixelPtr(coord[0], layer, 0);
102         }
103         else if (m_imParams.dim == IMG_DIM_2D || m_imParams.dim == IMG_DIM_CUBE)
104         {
105                 pixelPtr = m_pba[level].getPixelPtr(coord[0], coord[1], layer);
106         }
107         else
108         {
109                 pixelPtr = m_pba[level].getPixelPtr(coord[0], coord[1], coord[2]);
110         }
111
112         convertFormat(pixelPtr, mapVkFormat(m_imParams.format), m_internalFormat, resultMin, resultMax);
113 }
114
115 void SampleVerifier::fetchTexel (const IVec3&   coordIn,
116                                                                  int                    layer,
117                                                                  int                    level,
118                                                                  VkFilter               filter,
119                                                                  Vec4&                  resultMin,
120                                                                  Vec4&                  resultMax) const
121 {
122         IVec3 coord = coordIn;
123
124         VkSamplerAddressMode wrappingModes[] =
125         {
126                 m_samplerParams.wrappingModeU,
127                 m_samplerParams.wrappingModeV,
128                 m_samplerParams.wrappingModeW
129         };
130
131         const bool isSrgb = isSrgbFormat(m_imParams.format);
132
133         // Wrapping operations
134
135
136         if (m_imParams.dim == IMG_DIM_CUBE && filter == VK_FILTER_LINEAR)
137         {
138                 // If the image is a cubemap and we are using linear filtering, we do edge or corner wrapping
139
140                 const int       arrayLayer = layer / 6;
141                 int                     arrayFace  = layer % 6;
142
143                 if (coordOutOfRange(coord, 0, level) != coordOutOfRange(coord, 1, level))
144                 {
145                         // Wrap around edge
146
147                         IVec2   newCoord(0);
148                         int             newFace = 0;
149
150                         wrapCubemapEdge(coord.swizzle(0, 1),
151                                                         m_pba[level].getSize().swizzle(0, 1),
152                                                         arrayFace,
153                                                         newCoord,
154                                                         newFace);
155
156                         coord.xy()      = newCoord;
157                         layer           = arrayLayer * 6 + newFace;
158                 }
159                 else if (coordOutOfRange(coord, 0, level) && coordOutOfRange(coord, 1, level))
160                 {
161                         // Wrap corner
162
163                         int   faces[3] = {arrayFace, 0, 0};
164                         IVec2 cornerCoords[3];
165
166                         wrapCubemapCorner(coord.swizzle(0, 1),
167                                                           m_pba[level].getSize().swizzle(0, 1),
168                                                           arrayFace,
169                                                           faces[1],
170                                                           faces[2],
171                                                           cornerCoords[0],
172                                                           cornerCoords[1],
173                                                           cornerCoords[2]);
174
175                         // \todo [2016-08-01 collinbaker] Call into fetchTexelWrapped instead
176
177                         Vec4 cornerTexels[3];
178
179                         for (int ndx = 0; ndx < 3; ++ndx)
180                         {
181                                 int cornerLayer = faces[ndx] + arrayLayer * 6;
182
183                                 if (isSrgb)
184                                 {
185                                     cornerTexels[ndx] += sRGBToLinear(m_pba[level].getPixel(cornerCoords[ndx][0], cornerCoords[ndx][1], cornerLayer));
186                                 }
187                                 else
188                                 {
189                                         cornerTexels[ndx] += m_pba[level].getPixel(cornerCoords[ndx][0], cornerCoords[ndx][1], cornerLayer);
190                                 }
191                         }
192
193                         for (int compNdx = 0; compNdx < 4; ++compNdx)
194                         {
195                                 float compMin = cornerTexels[0][compNdx];
196                                 float compMax = cornerTexels[0][compNdx];
197
198                                 for (int ndx = 1; ndx < 3; ++ndx)
199                                 {
200                                         const float comp = cornerTexels[ndx][compNdx];
201
202                                         compMin = de::min(comp, compMin);
203                                         compMax = de::max(comp, compMax);
204                                 }
205
206                                 resultMin[compNdx] = compMin;
207                                 resultMax[compNdx] = compMax;
208                         }
209
210                         return;
211                 }
212                 else
213                 {
214                         // If no wrapping is necessary, just do nothing
215                 }
216         }
217         else
218         {
219                 // Otherwise, we do normal wrapping
220
221                 if (m_imParams.dim == IMG_DIM_CUBE)
222                 {
223                         wrappingModes[0] = wrappingModes[1] = wrappingModes[2] = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
224                 }
225
226                 for (int compNdx = 0; compNdx < 3; ++compNdx)
227                 {
228                         const int size = m_pba[level].getSize()[compNdx];
229
230                         coord[compNdx] = wrapTexelCoord(coord[compNdx], size, wrappingModes[compNdx]);
231                 }
232         }
233
234         if (coordOutOfRange(coord, 0, level) ||
235                 coordOutOfRange(coord, 1, level) ||
236                 coordOutOfRange(coord, 2, level))
237         {
238                 // If after wrapping coordinates are still out of range, perform texel replacement
239
240                 switch (m_samplerParams.borderColor)
241                 {
242                         case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
243                         {
244                                 resultMin = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
245                                 resultMax = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
246                                 return;
247                         }
248                         case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
249                         {
250                                 resultMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
251                                 resultMax = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
252                                 return;
253                         }
254                         case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
255                         {
256                                 resultMin = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
257                                 resultMax = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
258                                 return;
259                         }
260                         default:
261                         {
262                                 // \\ [2016-07-07 collinbaker] Handle
263                                 // VK_BORDER_COLOR_INT_* borders
264                                 DE_FATAL("Not implemented");
265                                 break;
266                         }
267                 }
268         }
269         else
270         {
271                 // Otherwise, actually fetch a texel
272
273             fetchTexelWrapped(coord, layer, level, resultMin, resultMax);
274         }
275 }
276
277 void SampleVerifier::getFilteredSample1D (const IVec3&  texelBase,
278                                                                                   float                 weight,
279                                                                                   int                   layer,
280                                                                                   int                   level,
281                                                                                   Vec4&                 resultMin,
282                                                                                   Vec4&                 resultMax) const
283 {
284         Vec4 texelsMin[2];
285         Vec4 texelsMax[2];
286
287         for (int i = 0; i < 2; ++i)
288         {
289             fetchTexel(texelBase + IVec3(i, 0, 0), layer, level, VK_FILTER_LINEAR, texelsMin[i], texelsMax[i]);
290         }
291
292         Interval resultIntervals[4];
293
294         for (int ndx = 0; ndx < 4; ++ndx)
295         {
296                 resultIntervals[ndx] = Interval(0.0);
297         }
298
299     for (int i = 0; i < 2; ++i)
300         {
301                 const Interval weightInterval = m_internalFormat.roundOut(Interval(i == 0 ? 1.0f - weight : weight), false);
302
303                 for (int compNdx = 0; compNdx < 4; ++compNdx)
304                 {
305                         const Interval texelInterval(false, texelsMin[i][compNdx], texelsMax[i][compNdx]);
306
307                         resultIntervals[compNdx] = m_internalFormat.roundOut(resultIntervals[compNdx] + weightInterval * texelInterval, false);
308                 }
309         }
310
311         for (int compNdx = 0; compNdx < 4; ++compNdx)
312         {
313                 resultMin[compNdx] = (float)resultIntervals[compNdx].lo();
314                 resultMax[compNdx] = (float)resultIntervals[compNdx].hi();
315         }
316 }
317
318
319 void SampleVerifier::getFilteredSample2D (const IVec3&  texelBase,
320                                                                                   const Vec2&   weights,
321                                                                                   int                   layer,
322                                                                                   int                   level,
323                                                                                   Vec4&                 resultMin,
324                                                                                   Vec4&                 resultMax) const
325 {
326         Vec4 texelsMin[4];
327         Vec4 texelsMax[4];
328
329         for (int i = 0; i < 2; ++i)
330         {
331                 for (int j = 0; j < 2; ++j)
332                 {
333                     fetchTexel(texelBase + IVec3(i, j, 0), layer, level, VK_FILTER_LINEAR, texelsMin[2 * j + i], texelsMax[2 * j + i]);
334                 }
335         }
336
337         Interval resultIntervals[4];
338
339         for (int ndx = 0; ndx < 4; ++ndx)
340         {
341                 resultIntervals[ndx] = Interval(0.0);
342         }
343
344         for (int i = 0; i < 2; ++i)
345         {
346                 const Interval iWeightInterval = m_internalFormat.roundOut(Interval(i == 0 ? 1.0f - weights[1] : weights[1]), false);
347
348                 for (int j = 0; j < 2; ++j)
349                 {
350                     const Interval jWeightInterval = m_internalFormat.roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[0] : weights[0]), false);
351
352                         for (int compNdx = 0; compNdx < 4; ++compNdx)
353                         {
354                                 const Interval texelInterval(false, texelsMin[2 * i + j][compNdx], texelsMax[2 * i + j][compNdx]);
355
356                                 resultIntervals[compNdx] = m_internalFormat.roundOut(resultIntervals[compNdx] + jWeightInterval * texelInterval, false);
357                         }
358                 }
359         }
360
361         for (int compNdx = 0; compNdx < 4; ++compNdx)
362         {
363                 resultMin[compNdx] = (float)resultIntervals[compNdx].lo();
364                 resultMax[compNdx] = (float)resultIntervals[compNdx].hi();
365         }
366 }
367
368 void SampleVerifier::getFilteredSample3D (const IVec3&  texelBase,
369                                                                                   const Vec3&   weights,
370                                                                                   int                   layer,
371                                                                                   int                   level,
372                                                                                   Vec4&                 resultMin,
373                                                                                   Vec4&                 resultMax) const
374 {
375         Vec4 texelsMin[8];
376         Vec4 texelsMax[8];
377
378         for (int i = 0; i < 2; ++i)
379         {
380                 for (int j = 0; j < 2; ++j)
381                 {
382                         for (int k = 0; k < 2; ++k)
383                         {
384                             fetchTexel(texelBase + IVec3(i, j, k), layer, level, VK_FILTER_LINEAR, texelsMin[4 * k + 2 * j + i], texelsMax[4 * k + 2 * j + i]);
385                         }
386                 }
387         }
388
389     Interval resultIntervals[4];
390
391         for (int ndx = 0; ndx < 4; ++ndx)
392         {
393                 resultIntervals[ndx] = Interval(0.0);
394         }
395
396         for (int i = 0; i < 2; ++i)
397         {
398             const Interval iWeightInterval = m_internalFormat.roundOut(Interval(i == 0 ? 1.0f - weights[2] : weights[2]), false);
399
400                 for (int j = 0; j < 2; ++j)
401                 {
402                     const Interval jWeightInterval = m_internalFormat.roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[1] : weights[1]), false);
403
404                         for (int k = 0; k < 2; ++k)
405                         {
406                             const Interval kWeightInterval = m_internalFormat.roundOut(jWeightInterval * Interval(k == 0 ? 1.0f - weights[0] : weights[0]), false);
407
408                                 for (int compNdx = 0; compNdx < 4; ++compNdx)
409                                 {
410                                         const Interval texelInterval(false, texelsMin[4 * i + 2 * j + k][compNdx], texelsMax[4 * i + 2 * j + k][compNdx]);
411
412                                         resultIntervals[compNdx] = m_internalFormat.roundOut(resultIntervals[compNdx] + kWeightInterval * texelInterval, false);
413                                 }
414                         }
415                 }
416         }
417
418         for (int compNdx = 0; compNdx < 4; ++compNdx)
419         {
420                 resultMin[compNdx] = (float)resultIntervals[compNdx].lo();
421                 resultMax[compNdx] = (float)resultIntervals[compNdx].hi();
422         }
423 }
424
425 void SampleVerifier::getFilteredSample (const IVec3&    texelBase,
426                                                                                 const Vec3&             weights,
427                                                                                 int                             layer,
428                                                                                 int                             level,
429                                                                                 Vec4&                   resultMin,
430                                                                                 Vec4&                   resultMax) const
431 {
432         DE_ASSERT(layer < m_imParams.arrayLayers);
433         DE_ASSERT(level < m_imParams.levels);
434
435         if (m_imParams.dim == IMG_DIM_1D)
436         {
437                 getFilteredSample1D(texelBase, weights.x(), layer, level, resultMin, resultMax);
438         }
439         else if (m_imParams.dim == IMG_DIM_2D || m_imParams.dim == IMG_DIM_CUBE)
440         {
441                 getFilteredSample2D(texelBase, weights.swizzle(0, 1), layer, level, resultMin, resultMax);
442         }
443         else
444         {
445                 getFilteredSample3D(texelBase, weights, layer, level, resultMin, resultMax);
446         }
447 }
448
449 void SampleVerifier::getMipmapStepBounds (const Vec2&   lodFracBounds,
450                                                                                   deInt32&              stepMin,
451                                                                                   deInt32&              stepMax) const
452 {
453         DE_ASSERT(m_mipmapBits < 32);
454         const int mipmapSteps = ((int)1) << m_mipmapBits;
455
456         stepMin = deFloorFloatToInt32(lodFracBounds[0] * (float)mipmapSteps);
457         stepMax = deCeilFloatToInt32 (lodFracBounds[1] * (float)mipmapSteps);
458
459         stepMin = de::max(stepMin, (deInt32)0);
460         stepMax = de::min(stepMax, (deInt32)mipmapSteps);
461 }
462
463 bool SampleVerifier::verifySampleFiltered (const Vec4&                  result,
464                                                                                    const IVec3&                 baseTexelHiIn,
465                                                                                    const IVec3&                 baseTexelLoIn,
466                                                                                    const IVec3&                 texelGridOffsetHiIn,
467                                                                                    const IVec3&                 texelGridOffsetLoIn,
468                                                                                    int                                  layer,
469                                                                                    int                                  levelHi,
470                                                                                    const Vec2&                  lodFracBounds,
471                                                                                    VkFilter                             filter,
472                                                                                    VkSamplerMipmapMode  mipmapFilter,
473                                                                                    std::ostream&                report) const
474 {
475         DE_ASSERT(layer < m_imParams.arrayLayers);
476         DE_ASSERT(levelHi < m_imParams.levels);
477
478         const int       coordSteps                      = 1 << m_coordBits;
479         const int       lodSteps                        = 1 << m_mipmapBits;
480         const int       levelLo                         = (levelHi < m_imParams.levels - 1) ? levelHi + 1 : levelHi;
481
482         IVec3           baseTexelHi                     = baseTexelHiIn;
483         IVec3           baseTexelLo                     = baseTexelLoIn;
484         IVec3           texelGridOffsetHi       = texelGridOffsetHiIn;
485         IVec3           texelGridOffsetLo       = texelGridOffsetLoIn;
486         deInt32         lodStepsMin                     = 0;
487         deInt32         lodStepsMax                     = 0;
488
489         getMipmapStepBounds(lodFracBounds, lodStepsMin, lodStepsMax);
490
491         report << "Testing at base texel " << baseTexelHi << ", " << baseTexelLo << " offset " << texelGridOffsetHi << ", " << texelGridOffsetLo << "\n";
492
493         Vec4 idealSampleHiMin;
494         Vec4 idealSampleHiMax;
495         Vec4 idealSampleLoMin;
496         Vec4 idealSampleLoMax;
497
498         // Get ideal samples at steps at each mipmap level
499
500         if (filter == VK_FILTER_LINEAR)
501         {
502                 // Adjust texel grid coordinates for linear filtering
503                 wrapTexelGridCoordLinear(baseTexelHi, texelGridOffsetHi, m_coordBits, m_imParams.dim);
504
505                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
506                 {
507                         wrapTexelGridCoordLinear(baseTexelLo, texelGridOffsetLo, m_coordBits, m_imParams.dim);
508                 }
509
510                 const Vec3 roundedWeightsHi = texelGridOffsetHi.asFloat() / (float)coordSteps;
511                 const Vec3 roundedWeightsLo = texelGridOffsetLo.asFloat() / (float)coordSteps;
512
513                 report << "Computed weights: " << roundedWeightsHi << ", " << roundedWeightsLo << "\n";
514
515             getFilteredSample(baseTexelHi, roundedWeightsHi, layer, levelHi, idealSampleHiMin, idealSampleHiMax);
516
517                 report << "Ideal hi sample: " << idealSampleHiMin << " through " << idealSampleHiMax << "\n";
518
519                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
520                 {
521                     getFilteredSample(baseTexelLo, roundedWeightsLo, layer, levelLo, idealSampleLoMin, idealSampleLoMax);
522
523                         report << "Ideal lo sample: " << idealSampleLoMin << " through " << idealSampleLoMax << "\n";
524                 }
525         }
526         else
527         {
528             fetchTexel(baseTexelHi, layer, levelHi, VK_FILTER_NEAREST, idealSampleHiMin, idealSampleHiMax);
529
530                 report << "Ideal hi sample: " << idealSampleHiMin << " through " << idealSampleHiMax << "\n";
531
532                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
533                 {
534                     fetchTexel(baseTexelLo, layer, levelLo, VK_FILTER_NEAREST, idealSampleLoMin, idealSampleLoMax);
535
536                         report << "Ideal lo sample: " << idealSampleLoMin << " through " << idealSampleLoMax << "\n";
537                 }
538         }
539
540         // Test ideal samples based on mipmap filtering mode
541
542         if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
543         {
544                 for (deInt32 lodStep = lodStepsMin; lodStep <= lodStepsMax; ++lodStep)
545                 {
546                         float weight = (float)lodStep / (float)lodSteps;
547
548                         report << "Testing at mipmap weight " << weight << "\n";
549
550                         Vec4 idealSampleMin;
551                         Vec4 idealSampleMax;
552
553                         for (int compNdx = 0; compNdx < 4; ++compNdx)
554                         {
555                                 const Interval idealSampleLo(false, idealSampleLoMin[compNdx], idealSampleLoMax[compNdx]);
556                                 const Interval idealSampleHi(false, idealSampleHiMin[compNdx], idealSampleHiMax[compNdx]);
557
558                                 const Interval idealSample
559                                         = m_internalFormat.roundOut(Interval(weight) * idealSampleLo + Interval(1.0f - weight) * idealSampleHi, false);
560
561                                 idealSampleMin[compNdx] = (float)idealSample.lo();
562                                 idealSampleMax[compNdx] = (float)idealSample.hi();
563                         }
564
565                         report << "Ideal sample: " << idealSampleMin << " through " << idealSampleMax << "\n";
566
567                         if (isInRange(result, idealSampleMin, idealSampleMax))
568                         {
569                                 return true;
570                         }
571                         else
572                         {
573                                 report << "Failed comparison\n";
574                         }
575                 }
576         }
577         else
578         {
579                 if (isInRange(result, idealSampleHiMin, idealSampleHiMax))
580                 {
581                         return true;
582                 }
583                 else
584                 {
585                         report << "Failed comparison\n";
586                 }
587         }
588
589         return false;
590 }
591
592 bool SampleVerifier::verifySampleTexelGridCoords (const SampleArguments&        args,
593                                                                                                   const Vec4&                           result,
594                                                                                                   const IVec3&                          gridCoordHi,
595                                                                                                   const IVec3&                          gridCoordLo,
596                                                                                                   const Vec2&                           lodBounds,
597                                                                                                   int                                           level,
598                                                                                                   VkSamplerMipmapMode           mipmapFilter,
599                                                                                                   std::ostream&                         report) const
600 {
601         const int       layer            = m_imParams.isArrayed ? (int)deRoundEven(args.layer) : 0U;
602         const IVec3 gridCoord[2] = {gridCoordHi, gridCoordLo};
603
604         IVec3 baseTexel[2];
605         IVec3 texelGridOffset[2];
606
607     for (int levelNdx = 0; levelNdx < 2; ++levelNdx)
608         {
609                 calcTexelBaseOffset(gridCoord[levelNdx], m_coordBits, baseTexel[levelNdx], texelGridOffset[levelNdx]);
610         }
611
612         const bool      canBeMinified  = lodBounds[1] > 0.0f;
613         const bool      canBeMagnified = lodBounds[0] <= 0.0f;
614
615         if (canBeMagnified)
616         {
617                 report << "Trying magnification...\n";
618
619                 if (m_samplerParams.magFilter == VK_FILTER_NEAREST)
620                 {
621                         report << "Testing against nearest texel at " << baseTexel[0] << "\n";
622
623                         Vec4 idealMin;
624                         Vec4 idealMax;
625
626                         fetchTexel(baseTexel[0], layer, level, VK_FILTER_NEAREST, idealMin, idealMax);
627
628                         if (isInRange(result, idealMin, idealMax))
629                     {
630                                 return true;
631                         }
632                         else
633                         {
634                                 report << "Failed against " << idealMin << " through " << idealMax << "\n";
635                         }
636                 }
637                 else
638                 {
639                         if  (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, Vec2(0.0f, 0.0f), VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, report))
640                                 return true;
641                 }
642         }
643
644         if (canBeMinified)
645         {
646                 report << "Trying minification...\n";
647
648                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
649                 {
650                         const Vec2 lodFracBounds = lodBounds - Vec2((float)level);
651
652                         if (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, lodFracBounds, m_samplerParams.minFilter, VK_SAMPLER_MIPMAP_MODE_LINEAR, report))
653                                 return true;
654                 }
655                 else if (m_samplerParams.minFilter == VK_FILTER_LINEAR)
656                 {
657                     if (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, Vec2(0.0f, 0.0f), VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, report))
658                                 return true;
659                 }
660                 else
661                 {
662                         report << "Testing against nearest texel at " << baseTexel[0] << "\n";
663
664                         Vec4 idealMin;
665                         Vec4 idealMax;
666
667                     fetchTexel(baseTexel[0], layer, level, VK_FILTER_NEAREST, idealMin, idealMax);
668
669                         if (isInRange(result, idealMin, idealMax))
670                     {
671                                 return true;
672                         }
673                         else
674                         {
675                                 report << "Failed against " << idealMin << " through " << idealMax << "\n";
676                         }
677                 }
678         }
679
680         return false;
681 }
682
683 bool SampleVerifier::verifySampleMipmapLevel (const SampleArguments&    args,
684                                                                                           const Vec4&                           result,
685                                                                                           const Vec4&                           coord,
686                                                                                           const Vec2&                           lodBounds,
687                                                                                           int                                           level,
688                                                                                           std::ostream&                         report) const
689 {
690         DE_ASSERT(level < m_imParams.levels);
691
692         VkSamplerMipmapMode mipmapFilter = m_samplerParams.mipmapFilter;
693
694         if (level == m_imParams.levels - 1)
695         {
696                 mipmapFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST;
697         }
698
699         Vec3    unnormalizedCoordMin[2];
700         Vec3    unnormalizedCoordMax[2];
701         IVec3   gridCoordMin[2];
702         IVec3   gridCoordMax[2];
703
704         const FloatFormat coordFormat(-32, 32, 16, true);
705
706         calcUnnormalizedCoordRange(coord,
707                                                            m_pba[level].getSize(),
708                                                            coordFormat,
709                                                            unnormalizedCoordMin[0],
710                                                            unnormalizedCoordMax[0]);
711
712         calcTexelGridCoordRange(unnormalizedCoordMin[0],
713                                                         unnormalizedCoordMax[0],
714                                                         m_coordBits,
715                                                         gridCoordMin[0],
716                                                         gridCoordMax[0]);
717
718         report << "Level " << level << " computed unnormalized coordinate range: [" << unnormalizedCoordMin[0] << ", " << unnormalizedCoordMax[0] << "]\n";
719         report << "Level " << level << " computed texel grid coordinate range: [" << gridCoordMin[0] << ", " << gridCoordMax[0] << "]\n";
720
721         if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
722         {
723                 calcUnnormalizedCoordRange(coord,
724                                                                    m_pba[level+1].getSize(),
725                                                                    coordFormat,
726                                                                    unnormalizedCoordMin[1],
727                                                                    unnormalizedCoordMax[1]);
728
729                 calcTexelGridCoordRange(unnormalizedCoordMin[1],
730                                                                 unnormalizedCoordMax[1],
731                                                                 m_coordBits,
732                                                                 gridCoordMin[1],
733                                                                 gridCoordMax[1]);
734
735
736                 report << "Level " << level+1 << " computed unnormalized coordinate range: [" << unnormalizedCoordMin[1] << " - " << unnormalizedCoordMax[1] << "]\n";
737                 report << "Level " << level+1 << " computed texel grid coordinate range: [" << gridCoordMin[1] << " - " << gridCoordMax[1] << "]\n";
738         }
739         else
740         {
741                 unnormalizedCoordMin[1] = unnormalizedCoordMax[1] = Vec3(0.0f);
742                 gridCoordMin[1] = gridCoordMax[1] = IVec3(0);
743         }
744
745         bool done = false;
746
747         IVec3 gridCoord[2] = {gridCoordMin[0], gridCoordMin[1]};
748
749     while (!done)
750         {
751                 if (verifySampleTexelGridCoords(args, result, gridCoord[0], gridCoord[1], lodBounds, level, mipmapFilter, report))
752                         return true;
753
754                 // Get next grid coordinate to test at
755
756                 // Represents whether the increment at a position wraps and should "carry" to the next place
757                 bool carry = true;
758
759                 for (int levelNdx = 0; levelNdx < 2; ++levelNdx)
760                 {
761                         for (int compNdx = 0; compNdx < 3; ++compNdx)
762                         {
763                                 if (carry)
764                                 {
765                                         deInt32& comp = gridCoord[levelNdx][compNdx];
766                                     ++comp;
767
768                                         if (comp > gridCoordMax[levelNdx][compNdx])
769                                         {
770                                                 comp = gridCoordMin[levelNdx][compNdx];
771                                         }
772                                         else
773                                         {
774                                                 carry = false;
775                                         }
776                                 }
777                         }
778                 }
779
780                 done = carry;
781         }
782
783         return false;
784 }
785
786 bool SampleVerifier::verifySampleCubemapFace (const SampleArguments&    args,
787                                                                                           const Vec4&                           result,
788                                                                                           const Vec4&                           coord,
789                                                                                           const Vec4&                           dPdx,
790                                                                                           const Vec4&                           dPdy,
791                                                                                           int                                           face,
792                                                                                           std::ostream&                         report) const
793 {
794         // Will use this parameter once cubemapping is implemented completely
795         DE_UNREF(face);
796
797         Vec2 lodBounds;
798
799         if (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
800         {
801                 float lodBias = m_samplerParams.lodBias;
802
803                 if (m_sampleLookupSettings.hasLodBias)
804                         lodBias += args.lodBias;
805
806                 lodBounds = calcLodBounds(dPdx.swizzle(0, 1, 2),
807                                                                   dPdy.swizzle(0, 1, 2),
808                                                                   m_imParams.size,
809                                                                   lodBias,
810                                                                   m_samplerParams.minLod,
811                                                                   m_samplerParams.maxLod);
812         }
813         else
814         {
815                 lodBounds[0] = lodBounds[1] = args.lod;
816         }
817
818         DE_ASSERT(lodBounds[0] <= lodBounds[1]);
819
820     const UVec2 levelBounds = calcLevelBounds(lodBounds, m_imParams.levels, m_samplerParams.mipmapFilter);
821
822         for (deUint32 level = levelBounds[0]; level <= levelBounds[1]; ++level)
823         {
824                 report << "Testing at mipmap level " << level << "...\n";
825
826                 const Vec2 levelLodBounds = calcLevelLodBounds(lodBounds, level);
827
828                 if (verifySampleMipmapLevel(args, result, coord, levelLodBounds, level, report))
829                 {
830                         return true;
831                 }
832
833                 report << "Done testing mipmap level " << level << ".\n\n";
834         }
835
836         return false;
837 }
838
839 bool SampleVerifier::verifySampleImpl (const SampleArguments&   args,
840                                                                            const Vec4&                          result,
841                                                                            std::ostream&                        report) const
842 {
843         // \todo [2016-07-11 collinbaker] Handle depth and stencil formats
844         // \todo [2016-07-06 collinbaker] Handle dRef
845         DE_ASSERT(m_samplerParams.isCompare == false);
846
847         Vec4    coord     = args.coord;
848         int coordSize = 0;
849
850         if (m_imParams.dim == IMG_DIM_1D)
851         {
852                 coordSize = 1;
853         }
854         else if (m_imParams.dim == IMG_DIM_2D)
855         {
856                 coordSize = 2;
857         }
858         else if (m_imParams.dim == IMG_DIM_3D || m_imParams.dim == IMG_DIM_CUBE)
859         {
860                 coordSize = 3;
861         }
862
863         // 15.6.1 Project operation
864
865         if (m_sampleLookupSettings.isProjective)
866         {
867                 DE_ASSERT(args.coord[coordSize] != 0.0f);
868                 const float proj = coord[coordSize];
869
870                 coord = coord / proj;
871         }
872
873         const Vec4 dPdx = (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES) ? args.dPdx : Vec4(0);
874         const Vec4 dPdy = (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES) ? args.dPdy : Vec4(0);
875
876         // 15.6.3 Cube Map Face Selection and Transformations
877
878         if (m_imParams.dim == IMG_DIM_CUBE)
879         {
880                 const Vec3      r                  = coord.swizzle(0, 1, 2);
881                 const Vec3      drdx       = dPdx.swizzle(0, 1, 2);
882                 const Vec3      drdy       = dPdy.swizzle(0, 1, 2);
883
884             int                 faceBitmap = calcCandidateCubemapFaces(r);
885
886                 // We must test every possible disambiguation order
887
888                 for (int faceNdx = 0; faceNdx < 6; ++faceNdx)
889                 {
890                         const bool isPossible = faceBitmap & (1U << faceNdx);
891
892                     if (!isPossible)
893                         {
894                                 continue;
895                         }
896
897                         Vec2 coordFace;
898                         Vec2 dPdxFace;
899                         Vec2 dPdyFace;
900
901                         calcCubemapFaceCoords(r, drdx, drdy, faceNdx, coordFace, dPdxFace, dPdyFace);
902
903                         if (verifySampleCubemapFace(args,
904                                                                                 result,
905                                                                                 Vec4(coordFace[0], coordFace[1], 0.0f, 0.0f),
906                                                                                 Vec4(dPdxFace[0], dPdxFace[1], 0.0f, 0.0f),
907                                                                                 Vec4(dPdyFace[0], dPdyFace[1], 0.0f, 0.0f),
908                                                                                 faceNdx,
909                                                                                 report))
910                         {
911                                 return true;
912                         }
913                 }
914
915                 return false;
916         }
917         else
918         {
919                 return verifySampleCubemapFace(args, result, coord, dPdx, dPdy, 0, report);
920         }
921 }
922
923 bool SampleVerifier::verifySampleReport (const SampleArguments& args,
924                                                                                  const Vec4&                    result,
925                                                                                  std::string&                   report) const
926 {
927         std::ostringstream reportStream;
928
929         const bool isValid = verifySampleImpl(args, result, reportStream);
930
931         report = reportStream.str();
932
933     return isValid;
934 }
935
936 bool SampleVerifier::verifySample (const SampleArguments&       args,
937                                                                    const Vec4&                          result) const
938 {
939         // Create unopened ofstream to simulate "null" ostream
940         std::ofstream nullStream;
941
942         return verifySampleImpl(args, result, nullStream);
943 }
944
945 } // texture_filtering
946 } // vkt