Fix missing dependency on sparse binds
[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 std::vector<de::SharedPtr<tcu::FloatFormat>>&     conversionPrecision,
71                                                                 const std::vector<de::SharedPtr<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         for (int compNdx = 0; compNdx < 4; ++compNdx)
306         {
307                 Interval resultInterval(0.0);
308
309                 for (int i = 0; i < 2; ++i)
310                 {
311                         const Interval  weightInterval  = m_filteringPrecision[compNdx]->roundOut(Interval(i == 0 ? 1.0f - weight : weight), false);
312                         const Interval  texelInterval   (false, texelsMin[i][compNdx], texelsMax[i][compNdx]);
313
314                         resultInterval = m_filteringPrecision[compNdx]->roundOut(resultInterval + weightInterval * texelInterval, false);
315                 }
316
317                 resultMin[compNdx] = (float)resultInterval.lo();
318                 resultMax[compNdx] = (float)resultInterval.hi();
319         }
320 }
321
322 void SampleVerifier::getFilteredSample2D (const IVec3&  texelBase,
323                                                                                   const Vec2&   weights,
324                                                                                   int                   layer,
325                                                                                   int                   level,
326                                                                                   Vec4&                 resultMin,
327                                                                                   Vec4&                 resultMax) const
328 {
329         Vec4 texelsMin[4];
330         Vec4 texelsMax[4];
331
332         for (int i = 0; i < 2; ++i)
333         {
334                 for (int j = 0; j < 2; ++j)
335                 {
336                     fetchTexel(texelBase + IVec3(i, j, 0), layer, level, VK_FILTER_LINEAR, texelsMin[2 * j + i], texelsMax[2 * j + i]);
337                 }
338         }
339
340         for (int compNdx = 0; compNdx < 4; ++compNdx)
341         {
342                 Interval resultInterval(0.0);
343
344                 for (int i = 0; i < 2; ++i)
345                 {
346                         const Interval iWeightInterval = m_filteringPrecision[compNdx]->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_filteringPrecision[compNdx]->roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[0] : weights[0]), false);
351                                 const Interval texelInterval(false, texelsMin[2 * i + j][compNdx], texelsMax[2 * i + j][compNdx]);
352
353                                 resultInterval = m_filteringPrecision[compNdx]->roundOut(resultInterval + jWeightInterval * texelInterval, false);
354                         }
355                 }
356
357                 resultMin[compNdx] = (float)resultInterval.lo();
358                 resultMax[compNdx] = (float)resultInterval.hi();
359         }
360 }
361
362 void SampleVerifier::getFilteredSample3D (const IVec3&  texelBase,
363                                                                                   const Vec3&   weights,
364                                                                                   int                   layer,
365                                                                                   int                   level,
366                                                                                   Vec4&                 resultMin,
367                                                                                   Vec4&                 resultMax) const
368 {
369         Vec4 texelsMin[8];
370         Vec4 texelsMax[8];
371
372         for (int i = 0; i < 2; ++i)
373         {
374                 for (int j = 0; j < 2; ++j)
375                 {
376                         for (int k = 0; k < 2; ++k)
377                         {
378                             fetchTexel(texelBase + IVec3(i, j, k), layer, level, VK_FILTER_LINEAR, texelsMin[4 * k + 2 * j + i], texelsMax[4 * k + 2 * j + i]);
379                         }
380                 }
381         }
382
383         for (int compNdx = 0; compNdx < 4; ++compNdx)
384         {
385                 Interval resultInterval(0.0);
386
387                 for (int i = 0; i < 2; ++i)
388                 {
389                         const Interval iWeightInterval = m_filteringPrecision[compNdx]->roundOut(Interval(i == 0 ? 1.0f - weights[2] : weights[2]), false);
390
391                         for (int j = 0; j < 2; ++j)
392                         {
393                                 const Interval jWeightInterval = m_filteringPrecision[compNdx]->roundOut(iWeightInterval * Interval(j == 0 ? 1.0f - weights[1] : weights[1]), false);
394
395                                 for (int k = 0; k < 2; ++k)
396                                 {
397                                         const Interval kWeightInterval = m_filteringPrecision[compNdx]->roundOut(jWeightInterval * Interval(k == 0 ? 1.0f - weights[0] : weights[0]), false);
398
399                                         const Interval texelInterval(false, texelsMin[4 * i + 2 * j + k][compNdx], texelsMax[4 * i + 2 * j + k][compNdx]);
400
401                                         resultInterval = m_filteringPrecision[compNdx]->roundOut(resultInterval + kWeightInterval * texelInterval, false);
402                                 }
403                         }
404                 }
405
406                 resultMin[compNdx] = (float)resultInterval.lo();
407                 resultMax[compNdx] = (float)resultInterval.hi();
408         }
409 }
410
411 void SampleVerifier::getFilteredSample (const IVec3&    texelBase,
412                                                                                 const Vec3&             weights,
413                                                                                 int                             layer,
414                                                                                 int                             level,
415                                                                                 Vec4&                   resultMin,
416                                                                                 Vec4&                   resultMax) const
417 {
418         DE_ASSERT(layer < m_imParams.arrayLayers);
419         DE_ASSERT(level < m_imParams.levels);
420
421         if (m_imParams.dim == IMG_DIM_1D)
422         {
423                 getFilteredSample1D(texelBase, weights.x(), layer, level, resultMin, resultMax);
424         }
425         else if (m_imParams.dim == IMG_DIM_2D || m_imParams.dim == IMG_DIM_CUBE)
426         {
427                 getFilteredSample2D(texelBase, weights.swizzle(0, 1), layer, level, resultMin, resultMax);
428         }
429         else
430         {
431                 getFilteredSample3D(texelBase, weights, layer, level, resultMin, resultMax);
432         }
433 }
434
435 void SampleVerifier::getMipmapStepBounds (const Vec2&   lodFracBounds,
436                                                                                   deInt32&              stepMin,
437                                                                                   deInt32&              stepMax) const
438 {
439         DE_ASSERT(m_mipmapBits < 32);
440         const int mipmapSteps = ((int)1) << m_mipmapBits;
441
442         stepMin = deFloorFloatToInt32(lodFracBounds[0] * (float)mipmapSteps);
443         stepMax = deCeilFloatToInt32 (lodFracBounds[1] * (float)mipmapSteps);
444
445         stepMin = de::max(stepMin, (deInt32)0);
446         stepMax = de::min(stepMax, (deInt32)mipmapSteps);
447 }
448
449 bool SampleVerifier::verifySampleFiltered (const Vec4&                  result,
450                                                                                    const IVec3&                 baseTexelHiIn,
451                                                                                    const IVec3&                 baseTexelLoIn,
452                                                                                    const IVec3&                 texelGridOffsetHiIn,
453                                                                                    const IVec3&                 texelGridOffsetLoIn,
454                                                                                    int                                  layer,
455                                                                                    int                                  levelHi,
456                                                                                    const Vec2&                  lodFracBounds,
457                                                                                    VkFilter                             filter,
458                                                                                    VkSamplerMipmapMode  mipmapFilter,
459                                                                                    std::ostream&                report) const
460 {
461         DE_ASSERT(layer < m_imParams.arrayLayers);
462         DE_ASSERT(levelHi < m_imParams.levels);
463
464         const int       coordSteps                      = 1 << m_coordBits;
465         const int       lodSteps                        = 1 << m_mipmapBits;
466         const int       levelLo                         = (levelHi < m_imParams.levels - 1) ? levelHi + 1 : levelHi;
467
468         IVec3           baseTexelHi                     = baseTexelHiIn;
469         IVec3           baseTexelLo                     = baseTexelLoIn;
470         IVec3           texelGridOffsetHi       = texelGridOffsetHiIn;
471         IVec3           texelGridOffsetLo       = texelGridOffsetLoIn;
472         deInt32         lodStepsMin                     = 0;
473         deInt32         lodStepsMax                     = 0;
474
475         getMipmapStepBounds(lodFracBounds, lodStepsMin, lodStepsMax);
476
477         report << "Testing at base texel " << baseTexelHi << ", " << baseTexelLo << " offset " << texelGridOffsetHi << ", " << texelGridOffsetLo << "\n";
478
479         Vec4 idealSampleHiMin;
480         Vec4 idealSampleHiMax;
481         Vec4 idealSampleLoMin;
482         Vec4 idealSampleLoMax;
483
484         // Get ideal samples at steps at each mipmap level
485
486         if (filter == VK_FILTER_LINEAR)
487         {
488                 // Adjust texel grid coordinates for linear filtering
489                 wrapTexelGridCoordLinear(baseTexelHi, texelGridOffsetHi, m_coordBits, m_imParams.dim);
490
491                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
492                 {
493                         wrapTexelGridCoordLinear(baseTexelLo, texelGridOffsetLo, m_coordBits, m_imParams.dim);
494                 }
495
496                 const Vec3 roundedWeightsHi = texelGridOffsetHi.asFloat() / (float)coordSteps;
497                 const Vec3 roundedWeightsLo = texelGridOffsetLo.asFloat() / (float)coordSteps;
498
499                 report << "Computed weights: " << roundedWeightsHi << ", " << roundedWeightsLo << "\n";
500
501             getFilteredSample(baseTexelHi, roundedWeightsHi, layer, levelHi, idealSampleHiMin, idealSampleHiMax);
502
503                 report << "Ideal hi sample: " << idealSampleHiMin << " through " << idealSampleHiMax << "\n";
504
505                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
506                 {
507                     getFilteredSample(baseTexelLo, roundedWeightsLo, layer, levelLo, idealSampleLoMin, idealSampleLoMax);
508
509                         report << "Ideal lo sample: " << idealSampleLoMin << " through " << idealSampleLoMax << "\n";
510                 }
511         }
512         else
513         {
514             fetchTexel(baseTexelHi, layer, levelHi, VK_FILTER_NEAREST, idealSampleHiMin, idealSampleHiMax);
515
516                 report << "Ideal hi sample: " << idealSampleHiMin << " through " << idealSampleHiMax << "\n";
517
518                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
519                 {
520                     fetchTexel(baseTexelLo, layer, levelLo, VK_FILTER_NEAREST, idealSampleLoMin, idealSampleLoMax);
521
522                         report << "Ideal lo sample: " << idealSampleLoMin << " through " << idealSampleLoMax << "\n";
523                 }
524         }
525
526         // Test ideal samples based on mipmap filtering mode
527
528         if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
529         {
530                 for (deInt32 lodStep = lodStepsMin; lodStep <= lodStepsMax; ++lodStep)
531                 {
532                         float weight = (float)lodStep / (float)lodSteps;
533
534                         report << "Testing at mipmap weight " << weight << "\n";
535
536                         Vec4 idealSampleMin;
537                         Vec4 idealSampleMax;
538
539                         for (int compNdx = 0; compNdx < 4; ++compNdx)
540                         {
541                                 const Interval idealSampleLo(false, idealSampleLoMin[compNdx], idealSampleLoMax[compNdx]);
542                                 const Interval idealSampleHi(false, idealSampleHiMin[compNdx], idealSampleHiMax[compNdx]);
543
544                                 const Interval idealSample
545                                         = m_filteringPrecision[compNdx]->roundOut(Interval(weight) * idealSampleLo + Interval(1.0f - weight) * idealSampleHi, false);
546
547                                 idealSampleMin[compNdx] = (float)idealSample.lo();
548                                 idealSampleMax[compNdx] = (float)idealSample.hi();
549                         }
550
551                         report << "Ideal sample: " << idealSampleMin << " through " << idealSampleMax << "\n";
552
553                         if (isInRange(result, idealSampleMin, idealSampleMax))
554                         {
555                                 return true;
556                         }
557                         else
558                         {
559                                 report << "Failed comparison\n";
560                         }
561                 }
562         }
563         else
564         {
565                 if (isInRange(result, idealSampleHiMin, idealSampleHiMax))
566                 {
567                         return true;
568                 }
569                 else
570                 {
571                         report << "Failed comparison\n";
572                 }
573         }
574
575         return false;
576 }
577
578 bool SampleVerifier::verifySampleTexelGridCoords (const SampleArguments&        args,
579                                                                                                   const Vec4&                           result,
580                                                                                                   const IVec3&                          gridCoordHi,
581                                                                                                   const IVec3&                          gridCoordLo,
582                                                                                                   const Vec2&                           lodBounds,
583                                                                                                   int                                           level,
584                                                                                                   VkSamplerMipmapMode           mipmapFilter,
585                                                                                                   std::ostream&                         report) const
586 {
587         const int       layer            = m_imParams.isArrayed ? (int)deRoundEven(args.layer) : 0U;
588         const IVec3 gridCoord[2] = {gridCoordHi, gridCoordLo};
589
590         IVec3 baseTexel[2];
591         IVec3 texelGridOffset[2];
592
593     for (int levelNdx = 0; levelNdx < 2; ++levelNdx)
594         {
595                 calcTexelBaseOffset(gridCoord[levelNdx], m_coordBits, baseTexel[levelNdx], texelGridOffset[levelNdx]);
596         }
597
598         const bool      canBeMinified  = lodBounds[1] > 0.0f;
599         const bool      canBeMagnified = lodBounds[0] <= 0.0f;
600
601         if (canBeMagnified)
602         {
603                 report << "Trying magnification...\n";
604
605                 if (m_samplerParams.magFilter == VK_FILTER_NEAREST)
606                 {
607                         report << "Testing against nearest texel at " << baseTexel[0] << "\n";
608
609                         Vec4 idealMin;
610                         Vec4 idealMax;
611
612                         fetchTexel(baseTexel[0], layer, level, VK_FILTER_NEAREST, idealMin, idealMax);
613
614                         if (isInRange(result, idealMin, idealMax))
615                     {
616                                 return true;
617                         }
618                         else
619                         {
620                                 report << "Failed against " << idealMin << " through " << idealMax << "\n";
621                         }
622                 }
623                 else
624                 {
625                         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))
626                                 return true;
627                 }
628         }
629
630         if (canBeMinified)
631         {
632                 report << "Trying minification...\n";
633
634                 if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
635                 {
636                         const Vec2 lodFracBounds = lodBounds - Vec2((float)level);
637
638                         if (verifySampleFiltered(result, baseTexel[0], baseTexel[1], texelGridOffset[0], texelGridOffset[1], layer, level, lodFracBounds, m_samplerParams.minFilter, VK_SAMPLER_MIPMAP_MODE_LINEAR, report))
639                                 return true;
640                 }
641                 else if (m_samplerParams.minFilter == VK_FILTER_LINEAR)
642                 {
643                     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))
644                                 return true;
645                 }
646                 else
647                 {
648                         report << "Testing against nearest texel at " << baseTexel[0] << "\n";
649
650                         Vec4 idealMin;
651                         Vec4 idealMax;
652
653                     fetchTexel(baseTexel[0], layer, level, VK_FILTER_NEAREST, idealMin, idealMax);
654
655                         if (isInRange(result, idealMin, idealMax))
656                     {
657                                 return true;
658                         }
659                         else
660                         {
661                                 report << "Failed against " << idealMin << " through " << idealMax << "\n";
662                         }
663                 }
664         }
665
666         return false;
667 }
668
669 bool SampleVerifier::verifySampleMipmapLevel (const SampleArguments&    args,
670                                                                                           const Vec4&                           result,
671                                                                                           const Vec4&                           coord,
672                                                                                           const Vec2&                           lodBounds,
673                                                                                           int                                           level,
674                                                                                           std::ostream&                         report) const
675 {
676         DE_ASSERT(level < m_imParams.levels);
677
678         VkSamplerMipmapMode mipmapFilter = m_samplerParams.mipmapFilter;
679
680         if (level == m_imParams.levels - 1)
681         {
682                 mipmapFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST;
683         }
684
685         Vec3    unnormalizedCoordMin[2];
686         Vec3    unnormalizedCoordMax[2];
687         IVec3   gridCoordMin[2];
688         IVec3   gridCoordMax[2];
689
690         const FloatFormat coordFormat(-32, 32, 16, true);
691
692         calcUnnormalizedCoordRange(coord,
693                                                            m_levels[level].getSize(),
694                                                            coordFormat,
695                                                            unnormalizedCoordMin[0],
696                                                            unnormalizedCoordMax[0]);
697
698         calcTexelGridCoordRange(unnormalizedCoordMin[0],
699                                                         unnormalizedCoordMax[0],
700                                                         m_coordBits,
701                                                         gridCoordMin[0],
702                                                         gridCoordMax[0]);
703
704         report << "Level " << level << " computed unnormalized coordinate range: [" << unnormalizedCoordMin[0] << ", " << unnormalizedCoordMax[0] << "]\n";
705         report << "Level " << level << " computed texel grid coordinate range: [" << gridCoordMin[0] << ", " << gridCoordMax[0] << "]\n";
706
707         if (mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
708         {
709                 calcUnnormalizedCoordRange(coord,
710                                                                    m_levels[level+1].getSize(),
711                                                                    coordFormat,
712                                                                    unnormalizedCoordMin[1],
713                                                                    unnormalizedCoordMax[1]);
714
715                 calcTexelGridCoordRange(unnormalizedCoordMin[1],
716                                                                 unnormalizedCoordMax[1],
717                                                                 m_coordBits,
718                                                                 gridCoordMin[1],
719                                                                 gridCoordMax[1]);
720
721
722                 report << "Level " << level+1 << " computed unnormalized coordinate range: [" << unnormalizedCoordMin[1] << " - " << unnormalizedCoordMax[1] << "]\n";
723                 report << "Level " << level+1 << " computed texel grid coordinate range: [" << gridCoordMin[1] << " - " << gridCoordMax[1] << "]\n";
724         }
725         else
726         {
727                 unnormalizedCoordMin[1] = unnormalizedCoordMax[1] = Vec3(0.0f);
728                 gridCoordMin[1] = gridCoordMax[1] = IVec3(0);
729         }
730
731         bool done = false;
732
733         IVec3 gridCoord[2] = {gridCoordMin[0], gridCoordMin[1]};
734
735     while (!done)
736         {
737                 if (verifySampleTexelGridCoords(args, result, gridCoord[0], gridCoord[1], lodBounds, level, mipmapFilter, report))
738                         return true;
739
740                 // Get next grid coordinate to test at
741
742                 // Represents whether the increment at a position wraps and should "carry" to the next place
743                 bool carry = true;
744
745                 for (int levelNdx = 0; levelNdx < 2; ++levelNdx)
746                 {
747                         for (int compNdx = 0; compNdx < 3; ++compNdx)
748                         {
749                                 if (carry)
750                                 {
751                                         deInt32& comp = gridCoord[levelNdx][compNdx];
752                                     ++comp;
753
754                                         if (comp > gridCoordMax[levelNdx][compNdx])
755                                         {
756                                                 comp = gridCoordMin[levelNdx][compNdx];
757                                         }
758                                         else
759                                         {
760                                                 carry = false;
761                                         }
762                                 }
763                         }
764                 }
765
766                 done = carry;
767         }
768
769         return false;
770 }
771
772 bool SampleVerifier::verifySampleCubemapFace (const SampleArguments&    args,
773                                                                                           const Vec4&                           result,
774                                                                                           const Vec4&                           coord,
775                                                                                           const Vec4&                           dPdx,
776                                                                                           const Vec4&                           dPdy,
777                                                                                           int                                           face,
778                                                                                           std::ostream&                         report) const
779 {
780         // Will use this parameter once cubemapping is implemented completely
781         DE_UNREF(face);
782
783         Vec2 lodBounds;
784
785         if (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
786         {
787                 float lodBias = m_samplerParams.lodBias;
788
789                 if (m_sampleLookupSettings.hasLodBias)
790                         lodBias += args.lodBias;
791
792                 lodBounds = calcLodBounds(dPdx.swizzle(0, 1, 2),
793                                                                   dPdy.swizzle(0, 1, 2),
794                                                                   m_imParams.size,
795                                                                   lodBias,
796                                                                   m_samplerParams.minLod,
797                                                                   m_samplerParams.maxLod);
798         }
799         else
800         {
801                 lodBounds[0] = lodBounds[1] = args.lod;
802         }
803
804         DE_ASSERT(lodBounds[0] <= lodBounds[1]);
805
806     const UVec2 levelBounds = calcLevelBounds(lodBounds, m_imParams.levels, m_samplerParams.mipmapFilter);
807
808         for (deUint32 level = levelBounds[0]; level <= levelBounds[1]; ++level)
809         {
810                 report << "Testing at mipmap level " << level << "...\n";
811
812                 const Vec2 levelLodBounds = calcLevelLodBounds(lodBounds, level);
813
814                 if (verifySampleMipmapLevel(args, result, coord, levelLodBounds, level, report))
815                 {
816                         return true;
817                 }
818
819                 report << "Done testing mipmap level " << level << ".\n\n";
820         }
821
822         return false;
823 }
824
825 bool SampleVerifier::verifySampleImpl (const SampleArguments&   args,
826                                                                            const Vec4&                          result,
827                                                                            std::ostream&                        report) const
828 {
829         // \todo [2016-07-11 collinbaker] Handle depth and stencil formats
830         // \todo [2016-07-06 collinbaker] Handle dRef
831         DE_ASSERT(m_samplerParams.isCompare == false);
832
833         Vec4    coord     = args.coord;
834         int coordSize = 0;
835
836         if (m_imParams.dim == IMG_DIM_1D)
837         {
838                 coordSize = 1;
839         }
840         else if (m_imParams.dim == IMG_DIM_2D)
841         {
842                 coordSize = 2;
843         }
844         else if (m_imParams.dim == IMG_DIM_3D || m_imParams.dim == IMG_DIM_CUBE)
845         {
846                 coordSize = 3;
847         }
848
849         // 15.6.1 Project operation
850
851         if (m_sampleLookupSettings.isProjective)
852         {
853                 DE_ASSERT(args.coord[coordSize] != 0.0f);
854                 const float proj = coord[coordSize];
855
856                 coord = coord / proj;
857         }
858
859         const Vec4 dPdx = (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES) ? args.dPdx : Vec4(0);
860         const Vec4 dPdy = (m_sampleLookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES) ? args.dPdy : Vec4(0);
861
862         // 15.6.3 Cube Map Face Selection and Transformations
863
864         if (m_imParams.dim == IMG_DIM_CUBE)
865         {
866                 const Vec3      r                  = coord.swizzle(0, 1, 2);
867                 const Vec3      drdx       = dPdx.swizzle(0, 1, 2);
868                 const Vec3      drdy       = dPdy.swizzle(0, 1, 2);
869
870             int                 faceBitmap = calcCandidateCubemapFaces(r);
871
872                 // We must test every possible disambiguation order
873
874                 for (int faceNdx = 0; faceNdx < 6; ++faceNdx)
875                 {
876                         const bool isPossible = ((faceBitmap & (1U << faceNdx)) != 0);
877
878                     if (!isPossible)
879                         {
880                                 continue;
881                         }
882
883                         Vec2 coordFace;
884                         Vec2 dPdxFace;
885                         Vec2 dPdyFace;
886
887                         calcCubemapFaceCoords(r, drdx, drdy, faceNdx, coordFace, dPdxFace, dPdyFace);
888
889                         if (verifySampleCubemapFace(args,
890                                                                                 result,
891                                                                                 Vec4(coordFace[0], coordFace[1], 0.0f, 0.0f),
892                                                                                 Vec4(dPdxFace[0], dPdxFace[1], 0.0f, 0.0f),
893                                                                                 Vec4(dPdyFace[0], dPdyFace[1], 0.0f, 0.0f),
894                                                                                 faceNdx,
895                                                                                 report))
896                         {
897                                 return true;
898                         }
899                 }
900
901                 return false;
902         }
903         else
904         {
905                 return verifySampleCubemapFace(args, result, coord, dPdx, dPdy, 0, report);
906         }
907 }
908
909 bool SampleVerifier::verifySampleReport (const SampleArguments& args,
910                                                                                  const Vec4&                    result,
911                                                                                  std::string&                   report) const
912 {
913         std::ostringstream reportStream;
914
915         const bool isValid = verifySampleImpl(args, result, reportStream);
916
917         report = reportStream.str();
918
919     return isValid;
920 }
921
922 bool SampleVerifier::verifySample (const SampleArguments&       args,
923                                                                    const Vec4&                          result) const
924 {
925         // Create unopened ofstream to simulate "null" ostream
926         std::ofstream nullStream;
927
928         return verifySampleImpl(args, result, nullStream);
929 }
930
931 } // texture
932 } // vkt