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