Improve precision handling in texture.explicit_lod
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / texture / vktTextureFilteringExplicitLodTests.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 Texture filtering tests with explicit LOD instructions
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktTextureFilteringExplicitLodTests.hpp"
25
26 #include "vkDefs.hpp"
27
28 #include "vktSampleVerifier.hpp"
29 #include "vktShaderExecutor.hpp"
30 #include "vktTestCaseUtil.hpp"
31
32 #include "vkDeviceUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkRef.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkStrUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkQueryUtil.hpp"
40
41 #include "tcuTexLookupVerifier.hpp"
42 #include "tcuTestLog.hpp"
43 #include "tcuTexture.hpp"
44 #include "tcuTextureUtil.hpp"
45 #include "tcuVector.hpp"
46
47 #include "deClock.h"
48 #include "deMath.h"
49 #include "deStringUtil.hpp"
50 #include "deUniquePtr.hpp"
51
52 #include <sstream>
53 #include <string>
54 #include <vector>
55
56 namespace vkt
57 {
58 namespace texture
59 {
60
61 using namespace tcu;
62 using namespace vk;
63 using std::string;
64
65 namespace
66 {
67
68 tcu::FloatFormat getConversionPrecision (VkFormat format)
69 {
70         const tcu::FloatFormat  reallyLow       (0, 0, 8, false, tcu::YES);
71         const tcu::FloatFormat  fp16            (-14, 15, 10, false);
72         const tcu::FloatFormat  fp32            (-126, 127, 23, true);
73
74         switch (format)
75         {
76             case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
77                 case VK_FORMAT_R5G6B5_UNORM_PACK16:
78                 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
79                         return reallyLow;
80
81                 case VK_FORMAT_R8_UNORM:
82                 case VK_FORMAT_R8_SNORM:
83                 case VK_FORMAT_R8G8_UNORM:
84                 case VK_FORMAT_R8G8_SNORM:
85                 case VK_FORMAT_R8G8B8A8_UNORM:
86                 case VK_FORMAT_R8G8B8A8_SNORM:
87                 case VK_FORMAT_B8G8R8A8_UNORM:
88                 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
89                 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
90                 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
91                         return fp16;
92
93                 case VK_FORMAT_R16_SFLOAT:
94                 case VK_FORMAT_R16G16_SFLOAT:
95                 case VK_FORMAT_R16G16B16A16_SFLOAT:
96                         return fp16;
97
98                 case VK_FORMAT_R32_SFLOAT:
99                 case VK_FORMAT_R32G32_SFLOAT:
100                 case VK_FORMAT_R32G32B32A32_SFLOAT:
101                         return fp32;
102
103                 default:
104                         DE_FATAL("Precision not defined for format");
105                         return fp32;
106         }
107 }
108
109 tcu::FloatFormat getFilteringPrecision (VkFormat format)
110 {
111         const tcu::FloatFormat  reallyLow       (0, 0, 6, false, tcu::YES);
112         const tcu::FloatFormat  low                     (0, 0, 7, false, tcu::YES);
113         const tcu::FloatFormat  fp16            (-14, 15, 10, false);
114         const tcu::FloatFormat  fp32            (-126, 127, 23, true);
115
116         switch (format)
117         {
118             case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
119                 case VK_FORMAT_R5G6B5_UNORM_PACK16:
120                 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
121                         return reallyLow;
122
123                 case VK_FORMAT_R8_UNORM:
124                 case VK_FORMAT_R8_SNORM:
125                 case VK_FORMAT_R8G8_UNORM:
126                 case VK_FORMAT_R8G8_SNORM:
127                 case VK_FORMAT_R8G8B8A8_UNORM:
128                 case VK_FORMAT_R8G8B8A8_SNORM:
129                 case VK_FORMAT_B8G8R8A8_UNORM:
130                 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
131                 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
132                 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
133                         return low;
134
135                 case VK_FORMAT_R16_SFLOAT:
136                 case VK_FORMAT_R16G16_SFLOAT:
137                 case VK_FORMAT_R16G16B16A16_SFLOAT:
138                         return fp16;
139
140                 case VK_FORMAT_R32_SFLOAT:
141                 case VK_FORMAT_R32G32_SFLOAT:
142                 case VK_FORMAT_R32G32B32A32_SFLOAT:
143                         return fp32;
144
145                 default:
146                         DE_FATAL("Precision not defined for format");
147                         return fp32;
148         }
149 }
150
151 using namespace shaderexecutor;
152
153 string genSamplerDeclaration(const ImageViewParameters& imParams,
154                                                          const SamplerParameters&       samplerParams)
155 {
156         string result = "sampler";
157
158         switch (imParams.dim)
159         {
160                 case IMG_DIM_1D:
161                         result += "1D";
162                         break;
163
164                 case IMG_DIM_2D:
165                         result += "2D";
166                         break;
167
168                 case IMG_DIM_3D:
169                         result += "3D";
170                         break;
171
172                 case IMG_DIM_CUBE:
173                         result += "Cube";
174                         break;
175
176                 default:
177                         break;
178         }
179
180         if (imParams.isArrayed)
181         {
182                 result += "Array";
183         }
184
185         if (samplerParams.isCompare)
186         {
187                 result += "Shadow";
188         }
189
190         return result;
191 }
192
193 string genLookupCode(const ImageViewParameters&         imParams,
194                                          const SamplerParameters&               samplerParams,
195                                          const SampleLookupSettings&    lookupSettings)
196 {
197         int dim = -1;
198
199         switch (imParams.dim)
200         {
201                 case IMG_DIM_1D:
202                         dim = 1;
203                         break;
204
205                 case IMG_DIM_2D:
206                         dim = 2;
207                         break;
208
209                 case IMG_DIM_3D:
210                         dim = 3;
211                         break;
212
213                 case IMG_DIM_CUBE:
214                         dim = 3;
215                         break;
216
217                 default:
218                         dim = 0;
219                         break;
220         }
221
222         DE_ASSERT(dim >= 1 && dim <= 3);
223
224         int numCoordComp = dim;
225
226         if (lookupSettings.isProjective)
227         {
228                 ++numCoordComp;
229         }
230
231         int numArgComp = numCoordComp;
232         bool hasSeparateCompare = false;
233
234         if (imParams.isArrayed)
235         {
236                 DE_ASSERT(!lookupSettings.isProjective && "Can't do a projective lookup on an arrayed image!");
237
238                 ++numArgComp;
239         }
240
241         if (samplerParams.isCompare && numCoordComp == 4)
242         {
243                 hasSeparateCompare = true;
244         }
245         else if (samplerParams.isCompare)
246         {
247                 ++numArgComp;
248         }
249
250         // Build coordinate input to texture*() function
251
252         string arg      = "vec";
253         arg += (char) (numArgComp + '0');
254         arg += "(vec";
255         arg += (char) (numCoordComp + '0');
256         arg += "(coord)";
257
258     int numZero = numArgComp - numCoordComp;
259
260         if (imParams.isArrayed)
261         {
262                 arg += ", layer";
263                 --numZero;
264         }
265
266         if (samplerParams.isCompare && !hasSeparateCompare)
267         {
268                 arg += ", dRef";
269                 --numZero;
270         }
271
272         for (int ndx = 0; ndx < numZero; ++ndx)
273         {
274                 arg += ", 0.0";
275         }
276
277         arg += ")";
278
279         // Build call to texture*() function
280
281         string code;
282
283         code += "result = texture";
284
285         if (lookupSettings.isProjective)
286         {
287                 code += "Proj";
288         }
289
290         if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
291         {
292                 code += "Grad";
293         }
294         else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
295         {
296                 code += "Lod";
297         }
298
299         code += "(testSampler, ";
300         code += arg;
301
302         if (samplerParams.isCompare && hasSeparateCompare)
303         {
304                 code += ", dRef";
305         }
306
307         if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
308         {
309                 code += ", vec";
310                 code += (char) (numCoordComp + '0');
311                 code += "(dPdx), ";
312                 code += "vec";
313                 code += (char) (numCoordComp + '0');
314                 code += "(dPdy)";
315         }
316         else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
317         {
318                 code += ", lod";
319         }
320
321         code += ");";
322
323         return code;
324 }
325
326 void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba, ImageViewParameters imParams)
327 {
328         const DeviceInterface& vkd = ctx.getDeviceInterface();
329         const VkDevice dev = ctx.getDevice();
330         const deUint32 uqfi = ctx.getUniversalQueueFamilyIndex();
331
332         const VkDeviceSize bufSize =
333                 getPixelSize(mapVkFormat(imParams.format))
334                 * imParams.arrayLayers
335                 * imParams.size[0]
336                 * imParams.size[1]
337                 * imParams.size[2]
338                 * 2;
339
340     const VkBufferCreateInfo bufCreateInfo =
341         {
342                 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,   // sType
343                 DE_NULL,                                                                // pNext
344                 0,                                                                              // flags
345                 bufSize,                                                                // size
346                 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,               // usage
347                 VK_SHARING_MODE_EXCLUSIVE,                              // sharingMode
348                 1,                                                                              // queueFamilyIndexCount
349                 &uqfi                                                                   // pQueueFamilyIndices
350         };
351
352         Unique<VkBuffer> buf(createBuffer(vkd, dev, &bufCreateInfo));
353
354         VkMemoryRequirements bufMemReq;
355         vkd.getBufferMemoryRequirements(dev, buf.get(), &bufMemReq);
356
357         de::UniquePtr<Allocation> bufMem(ctx.getDefaultAllocator().allocate(bufMemReq, MemoryRequirement::HostVisible));
358         VK_CHECK(vkd.bindBufferMemory(dev, buf.get(), bufMem->getMemory(), bufMem->getOffset()));
359
360         const VkCommandPoolCreateInfo copyPoolCreateInfo =
361         {
362                 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
363                 DE_NULL,
364                 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
365                 uqfi
366         };
367
368         Unique<VkCommandPool> copyPool(createCommandPool(vkd, dev, &copyPoolCreateInfo));
369
370         const VkCommandBufferAllocateInfo copyBufferCreateInfo =
371         {
372                 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
373                 DE_NULL,
374                 copyPool.get(),
375                 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
376                 1
377         };
378
379         Unique<VkCommandBuffer> copyBuffer(allocateCommandBuffer(vkd, dev, &copyBufferCreateInfo));
380
381         std::vector<VkBufferImageCopy> copyRegions;
382
383         deUint8* const bufMapPtr = reinterpret_cast<deUint8*>(bufMem->getHostPtr());
384         deUint8* bufCurPtr = bufMapPtr;
385
386         for (int level = 0; level < imParams.levels; ++level)
387         {
388                 const IVec3 curLevelSize = pba[level].getSize();
389
390                 const std::size_t copySize =
391                         getPixelSize(mapVkFormat(imParams.format))
392                         * curLevelSize[0] * curLevelSize[1] * curLevelSize[2]
393                         * imParams.arrayLayers;
394
395                 deMemcpy(bufCurPtr, pba[level].getDataPtr(), copySize);
396
397             flushMappedMemoryRange(vkd, dev, bufMem->getMemory(), bufMem->getOffset() + (bufCurPtr - bufMapPtr), copySize);
398
399                 const VkImageSubresourceLayers curSubresource =
400                 {
401                         VK_IMAGE_ASPECT_COLOR_BIT,
402                         (deUint32)level,
403                         0,
404                         (deUint32)imParams.arrayLayers
405                 };
406
407                 const VkBufferImageCopy curRegion =
408                 {
409                         (VkDeviceSize) (bufCurPtr - bufMapPtr),
410                         0,
411                         0,
412                         curSubresource,
413                         {0U, 0U, 0U},
414                         {(deUint32)curLevelSize[0], (deUint32)curLevelSize[1], (deUint32)curLevelSize[2]}
415                 };
416
417                 copyRegions.push_back(curRegion);
418
419                 bufCurPtr += copySize;
420         }
421
422         const VkCommandBufferBeginInfo beginInfo =
423         {
424                 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
425                 DE_NULL,
426                 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
427                 DE_NULL
428         };
429
430         VK_CHECK(vkd.beginCommandBuffer(copyBuffer.get(), &beginInfo));
431
432         const VkImageSubresourceRange imMemBarSubRange =
433         {
434                 VK_IMAGE_ASPECT_COLOR_BIT,
435                 0,
436                 (deUint32)imParams.levels,
437                 0,
438                 (deUint32)imParams.arrayLayers
439         };
440
441         VkImageMemoryBarrier imMemBar =
442         {
443                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
444                 DE_NULL,
445                 0,
446                 VK_ACCESS_TRANSFER_WRITE_BIT,
447                 VK_IMAGE_LAYOUT_UNDEFINED,
448                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
449                 VK_QUEUE_FAMILY_IGNORED,
450                 VK_QUEUE_FAMILY_IGNORED,
451                 im,
452                 imMemBarSubRange
453         };
454
455         VkBufferMemoryBarrier bufMemBar =
456         {
457                 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
458                 DE_NULL,
459                 VK_ACCESS_HOST_WRITE_BIT,
460                 VK_ACCESS_TRANSFER_READ_BIT,
461                 VK_QUEUE_FAMILY_IGNORED,
462                 VK_QUEUE_FAMILY_IGNORED,
463                 buf.get(),
464                 0,
465                 bufSize
466         };
467
468         vkd.cmdPipelineBarrier(copyBuffer.get(),
469                                                    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
470                                                    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
471                                                    0,
472                                                    0,
473                                                    DE_NULL,
474                                                    1,
475                                                    &bufMemBar,
476                                                    1,
477                                                    &imMemBar);
478
479         vkd.cmdCopyBufferToImage(copyBuffer.get(),
480                                                          buf.get(),
481                                                          im,
482                                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
483                                                          (deUint32)copyRegions.size(),
484                                                          &copyRegions[0]);
485
486         imMemBar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
487         imMemBar.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
488         imMemBar.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
489         imMemBar.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
490
491         vkd.cmdPipelineBarrier(copyBuffer.get(),
492                                                    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
493                                                    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
494                                                    0,
495                                                    0,
496                                                    DE_NULL,
497                                                    0,
498                                                    DE_NULL,
499                                                    1,
500                                                    &imMemBar);
501
502         VK_CHECK(vkd.endCommandBuffer(copyBuffer.get()));
503
504         const VkSubmitInfo copySubmitInfo =
505         {
506                 VK_STRUCTURE_TYPE_SUBMIT_INFO,
507                 DE_NULL,
508                 0,
509                 DE_NULL,
510                 DE_NULL,
511                 1,
512                 &(copyBuffer.get()),
513                 0,
514                 DE_NULL
515         };
516
517         VK_CHECK(vkd.queueSubmit(ctx.getUniversalQueue(), 1, &copySubmitInfo, 0));
518         VK_CHECK(vkd.queueWaitIdle(ctx.getUniversalQueue()));
519 }
520
521 struct TestCaseData
522 {
523         std::vector<ConstPixelBufferAccess>     pba;
524         ImageViewParameters                                     imParams;
525         SamplerParameters                                       samplerParams;
526         SampleLookupSettings                            sampleLookupSettings;
527         glu::ShaderType                                         shaderType;
528 };
529
530 VkSamplerCreateInfo mapSamplerCreateInfo (const SamplerParameters& samplerParams)
531 {
532         VkSamplerCreateInfo samplerCreateInfo =
533         {
534                 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,                          // sType
535                 DE_NULL,                                                                                        // pNext
536                 0U,                                                                                                     // flags
537             samplerParams.magFilter,                                                    // magFilter
538                 samplerParams.minFilter,                                                        // minFilter
539                 samplerParams.mipmapFilter,                                                     // mipmapMode
540             samplerParams.wrappingModeU,                                                // addressModeU
541             samplerParams.wrappingModeV,                                                // addressModeV
542             samplerParams.wrappingModeW,                                                // addressMoveW
543                 samplerParams.lodBias,                                                          // mipLodBias
544                 VK_FALSE,                                                                                       // anisotropyEnable
545                 1.0f,                                                                                           // maxAnisotropy
546                 VK_FALSE,                                                                                       // compareEnable
547                 VK_COMPARE_OP_NEVER,                                                            // compareOp
548                 samplerParams.minLod,                                                           // minLod
549                 samplerParams.maxLod,                                                           // maxLod
550             samplerParams.borderColor,                                                  // borderColor
551                 samplerParams.isUnnormalized ? VK_TRUE : VK_FALSE,      // unnormalizedCoordinates
552         };
553
554         if (samplerParams.isCompare)
555         {
556                 samplerCreateInfo.compareEnable = VK_TRUE;
557
558             DE_FATAL("Not implemented");
559         }
560
561         return samplerCreateInfo;
562 }
563
564 VkImageType mapImageType (ImgDim dim)
565 {
566         VkImageType imType;
567
568         switch (dim)
569         {
570                 case IMG_DIM_1D:
571                         imType = VK_IMAGE_TYPE_1D;
572                         break;
573
574                 case IMG_DIM_2D:
575                 case IMG_DIM_CUBE:
576                         imType = VK_IMAGE_TYPE_2D;
577                         break;
578
579                 case IMG_DIM_3D:
580                         imType = VK_IMAGE_TYPE_3D;
581                         break;
582
583                 default:
584                         imType = VK_IMAGE_TYPE_LAST;
585                         break;
586         }
587
588         return imType;
589 }
590
591 VkImageViewType mapImageViewType (const ImageViewParameters& imParams)
592 {
593         VkImageViewType imViewType;
594
595         if (imParams.isArrayed)
596         {
597                 switch (imParams.dim)
598                 {
599                         case IMG_DIM_1D:
600                                 imViewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
601                                 break;
602
603                         case IMG_DIM_2D:
604                                 imViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
605                                 break;
606
607                         case IMG_DIM_CUBE:
608                                 imViewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
609                                 break;
610
611                         default:
612                                 imViewType = VK_IMAGE_VIEW_TYPE_LAST;
613                                 break;
614                 }
615         }
616         else
617         {
618                 switch (imParams.dim)
619                 {
620                         case IMG_DIM_1D:
621                                 imViewType = VK_IMAGE_VIEW_TYPE_1D;
622                                 break;
623
624                         case IMG_DIM_2D:
625                                 imViewType = VK_IMAGE_VIEW_TYPE_2D;
626                                 break;
627
628                         case IMG_DIM_3D:
629                                 imViewType = VK_IMAGE_VIEW_TYPE_3D;
630                                 break;
631
632                         case IMG_DIM_CUBE:
633                                 imViewType = VK_IMAGE_VIEW_TYPE_CUBE;
634                                 break;
635
636                         default:
637                                 imViewType = VK_IMAGE_VIEW_TYPE_LAST;
638                                 break;
639                 }
640         }
641
642         return imViewType;
643 }
644
645 class DataGenerator
646 {
647 public:
648         virtual                                                                         ~DataGenerator  (void) {}
649
650         virtual bool                                                            generate                (void) = 0;
651
652         virtual std::vector<ConstPixelBufferAccess> getPba                      (void) const = 0;
653         virtual std::vector<SampleArguments>            getSampleArgs   (void) const = 0;
654
655 protected:
656                                                                                                 DataGenerator   (void) {}
657 };
658
659 class TextureFilteringTestInstance : public TestInstance
660 {
661 public:
662                                                                                 TextureFilteringTestInstance    (Context&                                       ctx,
663                                                                                                                                                  const TestCaseData&            testCaseData,
664                                                                                                                                                  ShaderExecutor&                        shaderExecutor,
665                                                                                                                                                  de::MovePtr<DataGenerator>     gen);
666
667         virtual TestStatus                                      iterate                                                 (void) { return runTest(); }
668
669 protected:
670         TestStatus                                                      runTest                                                 (void);
671         bool                                                            isSupported                                             (void);
672         void                                                            createResources                                 (void);
673         void                                                            execute                                                 (void);
674         bool                                                            verify                                                  (void);
675
676         tcu::Sampler                                            mapTcuSampler                                   (void) const;
677
678         const ImageViewParameters                       m_imParams;
679         const SamplerParameters                         m_samplerParams;
680         const SampleLookupSettings                      m_sampleLookupSettings;
681
682         std::vector<SampleArguments>            m_sampleArguments;
683         deUint32                                                        m_numSamples;
684
685         ShaderExecutor&                                         m_shaderExecutor;
686
687         de::MovePtr<Allocation>                         m_imAllocation;
688         Move<VkImage>                                           m_im;
689         Move<VkImageView>                                       m_imView;
690         Move<VkSampler>                                         m_sampler;
691
692         std::vector<ConstPixelBufferAccess> m_levels;
693         de::MovePtr<DataGenerator>                      m_gen;
694
695         std::vector<Vec4>                                       m_resultSamples;
696         std::vector<Vec4>                                       m_resultCoords;
697 };
698
699 TextureFilteringTestInstance::TextureFilteringTestInstance (Context&                                    ctx,
700                                                                                                                         const TestCaseData&                     testCaseData,
701                                                                                                                         ShaderExecutor&                         shaderExecutor,
702                                                                                                                         de::MovePtr<DataGenerator>      gen)
703         : TestInstance                          (ctx)
704         , m_imParams                            (testCaseData.imParams)
705         , m_samplerParams                       (testCaseData.samplerParams)
706         , m_sampleLookupSettings        (testCaseData.sampleLookupSettings)
707         , m_shaderExecutor                      (shaderExecutor)
708         , m_levels                                      (testCaseData.pba)
709         , m_gen                                         (gen.release())
710 {
711         for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
712                 DE_ASSERT(m_imParams.size[compNdx] > 0);
713 }
714
715 TestStatus TextureFilteringTestInstance::runTest (void)
716 {
717         if (!isSupported())
718             TCU_THROW(NotSupportedError, "Unsupported combination of filtering and image format");
719
720         TCU_CHECK(m_gen->generate());
721         m_levels = m_gen->getPba();
722
723         m_sampleArguments = m_gen->getSampleArgs();
724         m_numSamples = (deUint32)m_sampleArguments.size();
725
726         createResources();
727         initializeImage(m_context, m_im.get(), &m_levels[0], m_imParams);
728
729         m_shaderExecutor.addSamplerUniform(0, m_imView.get(), m_sampler.get());
730
731         deUint64 startTime, endTime;
732
733         startTime = deGetMicroseconds();
734         execute();
735         endTime = deGetMicroseconds();
736
737         m_context.getTestContext().getLog() << TestLog::Message
738                                                                                 << "Execution time: "
739                                                                                 << endTime - startTime
740                                                                                 << "us"
741                                                                                 << TestLog::EndMessage;
742
743     startTime = deGetMicroseconds();
744         bool result = verify();
745     endTime = deGetMicroseconds();
746
747         m_context.getTestContext().getLog() << TestLog::Message
748                                                                                 << "Verification time: "
749                                                                                 << endTime - startTime
750                                                                                 << "us"
751                                                                                 << TestLog::EndMessage;
752
753         if (result)
754         {
755                 return TestStatus::pass("Success");
756         }
757         else
758         {
759                 // \todo [2016-06-24 collinbaker] Print report if verification fails
760                 return TestStatus::fail("Verification failed");
761         }
762 }
763
764 bool TextureFilteringTestInstance::verify (void)
765 {
766         // \todo [2016-06-24 collinbaker] Handle cubemaps
767
768         const int                               coordBits                       = (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits;
769         const int                               mipmapBits                      = (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits;
770         const int                               maxPrintedFailures      = 5;
771         int                                             failCount                       = 0;
772
773         const SampleVerifier    verifier                        (m_imParams,
774                                                                                                  m_samplerParams,
775                                                                                                  m_sampleLookupSettings,
776                                                                                                  coordBits,
777                                                                                                  mipmapBits,
778                                                                                                  getConversionPrecision(m_imParams.format),
779                                                                                                  getFilteringPrecision(m_imParams.format),
780                                                                                                  m_levels);
781
782
783         for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
784         {
785                 if (!verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]))
786                 {
787                         if (failCount++ < maxPrintedFailures)
788                         {
789                                 // Re-run with report logging
790                                 std::string report;
791                                 verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
792
793                                 m_context.getTestContext().getLog()
794                                         << TestLog::Section("Failed sample", "Failed sample")
795                                         << TestLog::Message
796                                         << "Sample " << sampleNdx << ".\n"
797                                         << "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
798                                         << "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
799                                         << "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n"
800                                         << "Failure report:\n" << report << "\n"
801                                         << TestLog::EndMessage
802                                         << TestLog::EndSection;
803                         }
804                 }
805         }
806
807         m_context.getTestContext().getLog()
808                 << TestLog::Message
809                 << "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
810                 << TestLog::EndMessage;
811
812         return failCount == 0;
813 }
814
815 void TextureFilteringTestInstance::execute (void)
816 {
817         std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods;
818
819         for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
820         {
821                 const SampleArguments& sampleArgs = m_sampleArguments[ndx];
822
823                 for (deUint8 compNdx = 0; compNdx < 4; ++compNdx)
824                 {
825                         coords.push_back(sampleArgs.coord[compNdx]);
826                         dPdxs .push_back(sampleArgs.dPdx[compNdx]);
827                         dPdys .push_back(sampleArgs.dPdy[compNdx]);
828                 }
829
830                 layers.push_back(sampleArgs.layer);
831                 dRefs .push_back(sampleArgs.dRef);
832                 lods  .push_back(sampleArgs.lod);
833         }
834
835         const void* inputs[6] =
836         {
837                 reinterpret_cast<const void*>(&coords[0]),
838                 reinterpret_cast<const void*>(&layers[0]),
839                 reinterpret_cast<const void*>(&dRefs[0]),
840                 reinterpret_cast<const void*>(&dPdxs[0]),
841                 reinterpret_cast<const void*>(&dPdys[0]),
842                 reinterpret_cast<const void*>(&lods[0])
843         };
844
845         // Staging buffers; data will be copied into vectors of Vec4
846         // \todo [2016-06-24 collinbaker] Figure out if I actually need to
847         // use staging buffers
848         std::vector<float> resultSamplesTemp(m_numSamples * 4);
849         std::vector<float> resultCoordsTemp (m_numSamples * 4);
850
851         void* outputs[2] =
852         {
853                 reinterpret_cast<void*>(&resultSamplesTemp[0]),
854                 reinterpret_cast<void*>(&resultCoordsTemp[0])
855         };
856
857         m_shaderExecutor.execute(m_context, m_numSamples, inputs, outputs);
858
859         m_resultSamples.resize(m_numSamples);
860         m_resultCoords .resize(m_numSamples);
861
862         for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
863         {
864                 m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0],
865                                                                         resultSamplesTemp[4 * ndx + 1],
866                                                                         resultSamplesTemp[4 * ndx + 2],
867                                                                         resultSamplesTemp[4 * ndx + 3]);
868
869                 m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0],
870                                                                         resultCoordsTemp [4 * ndx + 1],
871                                                                         resultCoordsTemp [4 * ndx + 2],
872                                                                         resultCoordsTemp [4 * ndx + 3]);
873         }
874 }
875
876 void TextureFilteringTestInstance::createResources (void)
877 {
878         // Create VkImage
879
880         const DeviceInterface&          vkd                             = m_context.getDeviceInterface();
881         const VkDevice                          device                  = m_context.getDevice();
882
883         const deUint32                          queueFamily             = m_context.getUniversalQueueFamilyIndex();
884         const VkImageCreateFlags        imCreateFlags   =(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
885
886         const VkImageCreateInfo         imCreateInfo    =
887         {
888                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
889                 DE_NULL,
890                 imCreateFlags,
891             mapImageType(m_imParams.dim),
892             m_imParams.format,
893                 makeExtent3D(m_imParams.size[0], m_imParams.size[1], m_imParams.size[2]),
894             (deUint32)m_imParams.levels,
895             (deUint32)m_imParams.arrayLayers,
896                 VK_SAMPLE_COUNT_1_BIT,
897                 VK_IMAGE_TILING_OPTIMAL,
898                 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
899                 VK_SHARING_MODE_EXCLUSIVE,
900                 1,
901                 &queueFamily,
902                 VK_IMAGE_LAYOUT_UNDEFINED
903         };
904
905     m_im = createImage(vkd, device, &imCreateInfo);
906
907         // Allocate memory for image
908
909         VkMemoryRequirements imMemReq;
910         vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq);
911
912         m_imAllocation = m_context.getDefaultAllocator().allocate(imMemReq, MemoryRequirement::Any);
913         VK_CHECK(vkd.bindImageMemory(device, m_im.get(), m_imAllocation->getMemory(), m_imAllocation->getOffset()));
914
915         // Create VkImageView
916
917         // \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images)
918         DE_ASSERT(m_imParams.dim != IMG_DIM_CUBE); // \todo Support cube maps
919         const VkImageSubresourceRange imViewSubresourceRange =
920         {
921                 VK_IMAGE_ASPECT_COLOR_BIT,                      // aspectMask
922                 0,                                                                      // baseMipLevel
923                 (deUint32)m_imParams.levels,            // levelCount
924                 0,                                                                      // baseArrayLayer
925                 (deUint32)m_imParams.arrayLayers        // layerCount
926         };
927
928         const VkComponentMapping imViewCompMap =
929         {
930                 VK_COMPONENT_SWIZZLE_R,
931                 VK_COMPONENT_SWIZZLE_G,
932                 VK_COMPONENT_SWIZZLE_B,
933                 VK_COMPONENT_SWIZZLE_A
934         };
935
936         const VkImageViewCreateInfo imViewCreateInfo =
937         {
938                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,       // sType
939                 DE_NULL,                                                                        // pNext
940                 0,                                                                                      // flags
941                 m_im.get(),                                                                     // image
942                 mapImageViewType(m_imParams),                           // viewType
943             m_imParams.format,                                                  // format
944             imViewCompMap,                                                              // components
945                 imViewSubresourceRange                                          // subresourceRange
946         };
947
948         m_imView = createImageView(vkd, device, &imViewCreateInfo);
949
950         // Create VkSampler
951
952         const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams);
953         m_sampler = createSampler(vkd, device, &samplerCreateInfo);
954 }
955
956 VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams)
957 {
958         VkFormatFeatureFlags    features        = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
959
960         if (samplerParams.minFilter      == VK_FILTER_LINEAR ||
961                 samplerParams.magFilter  == VK_FILTER_LINEAR ||
962                 samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
963         {
964                 features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
965         }
966
967         return features;
968 }
969
970 bool TextureFilteringTestInstance::isSupported (void)
971 {
972         const VkImageCreateFlags                imCreateFlags           = (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
973         const VkFormatFeatureFlags              reqImFeatures           = getRequiredFormatFeatures(m_samplerParams);
974
975         const VkImageFormatProperties   imFormatProperties      = getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(),
976                                                                                                                                                                                                  m_context.getPhysicalDevice(),
977                                                                                                                                                                                                  m_imParams.format,
978                                                                                                                                                                                                  mapImageType(m_imParams.dim),
979                                                                                                                                                                                                  VK_IMAGE_TILING_OPTIMAL,
980                                                                                                                                                                                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
981                                                                                                                                                                                                  imCreateFlags);
982         const VkFormatProperties                formatProperties        = getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(),
983                                                                                                                                                                                         m_context.getPhysicalDevice(),
984                                                                                                                                                                                         m_imParams.format);
985
986         // \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties
987         DE_UNREF(imFormatProperties);
988
989         return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures;
990 }
991
992 class TextureFilteringTestCase : public TestCase
993 {
994 public:
995         TextureFilteringTestCase (tcu::TestContext&     testCtx,
996                                                           const char*           name,
997                                                           const char*           description)
998                 : TestCase(testCtx, name, description)
999         {
1000         }
1001
1002         void init (void);
1003
1004         virtual void initPrograms (vk::SourceCollections& programCollection) const
1005         {
1006                 DE_ASSERT(m_executor);
1007                 m_executor->setShaderSources(programCollection);
1008         }
1009
1010         virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0;
1011
1012         virtual TestInstance* createInstance (Context& ctx) const
1013         {
1014                 return new TextureFilteringTestInstance(ctx, m_testCaseData, *m_executor, createGenerator());
1015         }
1016
1017 protected:
1018         de::MovePtr<ShaderExecutor> m_executor;
1019         TestCaseData                            m_testCaseData;
1020 };
1021
1022 void TextureFilteringTestCase::init (void)
1023 {
1024         ShaderSpec shaderSpec;
1025         shaderSpec.source = genLookupCode(m_testCaseData.imParams,
1026                                                                           m_testCaseData.samplerParams,
1027                                                                           m_testCaseData.sampleLookupSettings);
1028         shaderSpec.source += "\nsampledCoord = coord;";
1029
1030         shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1031         shaderSpec.outputs.push_back(Symbol("sampledCoord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1032         shaderSpec.inputs .push_back(Symbol("coord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1033         shaderSpec.inputs .push_back(Symbol("layer", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
1034         shaderSpec.inputs .push_back(Symbol("dRef", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
1035         shaderSpec.inputs .push_back(Symbol("dPdx", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1036         shaderSpec.inputs .push_back(Symbol("dPdy", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1037         shaderSpec.inputs .push_back(Symbol("lod", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
1038
1039         shaderSpec.globalDeclarations = "layout(set=0, binding=0) uniform highp ";
1040         shaderSpec.globalDeclarations += genSamplerDeclaration(m_testCaseData.imParams,
1041                                                                                                                    m_testCaseData.samplerParams);
1042         shaderSpec.globalDeclarations += " testSampler;";
1043
1044         m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_testCaseData.shaderType, shaderSpec));
1045         DE_ASSERT(m_executor);
1046
1047         m_testCtx.getLog() << *m_executor;
1048 }
1049
1050 class Texture2DGradientTestCase : public TextureFilteringTestCase
1051 {
1052 public:
1053         Texture2DGradientTestCase (TestContext&                 testCtx,
1054                                                            const char*                  name,
1055                                                            const char*                  desc,
1056                                                            TextureFormat                format,
1057                                                            IVec3                                dimensions,
1058                                                            VkFilter                             magFilter,
1059                                                            VkFilter                             minFilter,
1060                                                            VkSamplerMipmapMode  mipmapFilter,
1061                                                            VkSamplerAddressMode wrappingMode,
1062                                                            bool                                 useDerivatives)
1063
1064                 : TextureFilteringTestCase      (testCtx, name, desc)
1065                 , m_format                                      (format)
1066                 , m_dimensions                          (dimensions)
1067                 , m_magFilter                           (magFilter)
1068                 , m_minFilter                           (minFilter)
1069                 , m_mipmapFilter                        (mipmapFilter)
1070                 , m_wrappingMode                        (wrappingMode)
1071                 , m_useDerivatives                      (useDerivatives)
1072         {
1073                 m_testCaseData = genTestCaseData();
1074                 init();
1075         }
1076
1077 protected:
1078         class Generator;
1079
1080         virtual de::MovePtr<DataGenerator> createGenerator (void) const;
1081
1082         TestCaseData genTestCaseData()
1083         {
1084                 // Generate grid
1085
1086                 const SampleLookupSettings sampleLookupSettings =
1087                 {
1088                         m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
1089                         false, // hasLodBias
1090                         false, // isProjective
1091                 };
1092
1093                 const SamplerParameters samplerParameters =
1094                 {
1095                         m_magFilter,
1096                         m_minFilter,
1097                         m_mipmapFilter,
1098                         m_wrappingMode,
1099                         m_wrappingMode,
1100                         m_wrappingMode,
1101                         VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1102                         0.0f,
1103                         -1.0f,
1104                         50.0f,
1105                         false,
1106                         false
1107                 };
1108
1109                 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0],
1110                                                                                                                                            m_dimensions[1])));
1111
1112                 const ImageViewParameters imParameters =
1113                 {
1114                         IMG_DIM_2D,
1115                         mapTextureFormat(m_format),
1116                         m_dimensions,
1117                         numLevels,
1118                         false,
1119                         1,
1120                 };
1121
1122                 const TestCaseData data =
1123                 {
1124                         std::vector<ConstPixelBufferAccess>(),
1125                         imParameters,
1126                         samplerParameters,
1127                         sampleLookupSettings,
1128                         glu::SHADERTYPE_FRAGMENT
1129                 };
1130
1131                 return data;
1132         }
1133
1134 private:
1135         const TextureFormat                     m_format;
1136         const IVec3                                     m_dimensions;
1137         const VkFilter                          m_magFilter;
1138         const VkFilter                          m_minFilter;
1139         const VkSamplerMipmapMode       m_mipmapFilter;
1140         const VkSamplerAddressMode      m_wrappingMode;
1141         const bool                                      m_useDerivatives;
1142 };
1143
1144 class Texture2DGradientTestCase::Generator : public DataGenerator
1145 {
1146 public:
1147         Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {}
1148
1149         virtual ~Generator (void)
1150         {
1151                 delete m_tex.release();
1152         }
1153
1154         virtual bool generate (void)
1155         {
1156                 m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format,
1157                                                                                                          m_testCase->m_dimensions[0],
1158                                                                                                          m_testCase->m_dimensions[1]));
1159
1160                 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0],
1161                                                                                                                                            m_testCase->m_dimensions[1])));
1162
1163                 const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format);
1164
1165                 const Vec4 cBias  = fmtInfo.valueMin;
1166                 const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
1167
1168                 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1169                 {
1170                         const Vec4 gMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
1171                         const Vec4 gMax = Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
1172
1173                         m_tex->allocLevel(levelNdx);
1174                         fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax);
1175                 }
1176
1177                 return true;
1178         }
1179
1180         virtual std::vector<ConstPixelBufferAccess> getPba (void) const
1181         {
1182                 std::vector<ConstPixelBufferAccess> pba;
1183
1184                 const deUint8 numLevels = (deUint8) m_tex->getNumLevels();
1185
1186                 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1187                 {
1188                         pba.push_back(m_tex->getLevel(levelNdx));
1189                 }
1190
1191                 return pba;
1192         }
1193
1194         virtual std::vector<SampleArguments> getSampleArgs (void) const
1195         {
1196                 std::vector<SampleArguments> args;
1197
1198                 if (m_testCase->m_useDerivatives)
1199                 {
1200                         struct
1201                         {
1202                                 Vec4 dPdx;
1203                                 Vec4 dPdy;
1204                         }
1205                         derivativePairs[] =
1206                         {
1207                                 {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1208                                 {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1209                                 {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1210                                 {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1211                                 {Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)}
1212                         };
1213
1214                         for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1215                         {
1216                                 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1217                                 {
1218                                     for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
1219                                         {
1220                                                 SampleArguments cur;
1221                                                 cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1222                                                                                  (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1223                                                                                  0.0f, 0.0f);
1224                                                 cur.dPdx = derivativePairs[derivNdx].dPdx;
1225                                                 cur.dPdy = derivativePairs[derivNdx].dPdy;
1226
1227                                                 args.push_back(cur);
1228                                         }
1229                                 }
1230                         }
1231                 }
1232                 else
1233                 {
1234                         const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
1235
1236                         for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1237                         {
1238                                 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1239                                 {
1240                                         for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
1241                                         {
1242                                                 SampleArguments cur;
1243                                                 cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1244                                                                                  (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1245                                                                                  0.0f, 0.0f);
1246                                                 cur.lod = lodList[lodNdx];
1247
1248                                                 args.push_back(cur);
1249                                         }
1250                                 }
1251                         }
1252                 }
1253
1254                 return args;
1255         }
1256
1257 private:
1258         const Texture2DGradientTestCase*        m_testCase;
1259         de::MovePtr<Texture2D>                          m_tex;
1260 };
1261
1262 de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const
1263 {
1264         return de::MovePtr<DataGenerator>(new Generator(this));
1265 }
1266
1267 TestCaseGroup* create2DFormatTests (TestContext& testCtx)
1268 {
1269         de::MovePtr<TestCaseGroup> tests(
1270                 new TestCaseGroup(testCtx, "formats", "Various image formats"));
1271
1272     const VkFormat formats[] =
1273         {
1274             VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1275                 VK_FORMAT_R5G6B5_UNORM_PACK16,
1276                 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1277                 VK_FORMAT_R8_UNORM,
1278                 VK_FORMAT_R8_SNORM,
1279                 VK_FORMAT_R8G8_UNORM,
1280                 VK_FORMAT_R8G8_SNORM,
1281                 VK_FORMAT_R8G8B8A8_UNORM,
1282                 VK_FORMAT_R8G8B8A8_SNORM,
1283 //              VK_FORMAT_R8G8B8A8_SRGB,
1284                 VK_FORMAT_B8G8R8A8_UNORM,
1285 //              VK_FORMAT_B8G8R8A8_SRGB,
1286                 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1287                 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1288 //              VK_FORMAT_A8B8G8R8_SRGB_PACK32,
1289                 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1290                 VK_FORMAT_R16_SFLOAT,
1291                 VK_FORMAT_R16G16_SFLOAT,
1292                 VK_FORMAT_R16G16B16A16_SFLOAT,
1293                 VK_FORMAT_R32_SFLOAT,
1294                 VK_FORMAT_R32G32_SFLOAT,
1295                 VK_FORMAT_R32G32B32A32_SFLOAT,
1296 //              VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1297 //              VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
1298         };
1299
1300         const IVec3 size(32, 32, 1);
1301
1302         for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
1303         {
1304                 const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
1305
1306                 Texture2DGradientTestCase* testCaseNearest =
1307                         new Texture2DGradientTestCase(
1308                                 testCtx,
1309                             (prefix + "_nearest").c_str(),
1310                                 "...",
1311                                 mapVkFormat(formats[formatNdx]),
1312                                 size,
1313                                 VK_FILTER_NEAREST,
1314                                 VK_FILTER_NEAREST,
1315                                 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1316                                 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1317                                 false);
1318
1319                 tests->addChild(testCaseNearest);
1320
1321             Texture2DGradientTestCase* testCaseLinear =
1322                         new Texture2DGradientTestCase(
1323                                 testCtx,
1324                             (prefix + "_linear").c_str(),
1325                                 "...",
1326                                 mapVkFormat(formats[formatNdx]),
1327                                 size,
1328                                 VK_FILTER_LINEAR,
1329                                 VK_FILTER_LINEAR,
1330                                 VK_SAMPLER_MIPMAP_MODE_LINEAR,
1331                                 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1332                                 false);
1333
1334                 tests->addChild(testCaseLinear);
1335         }
1336
1337         return tests.release();
1338 }
1339
1340 TestCaseGroup* create2DDerivTests (TestContext& testCtx)
1341 {
1342         de::MovePtr<TestCaseGroup> tests(
1343                 new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
1344
1345         const VkFormat                          format           = VK_FORMAT_R8G8B8A8_UNORM;
1346         const VkSamplerAddressMode      wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1347         const IVec3                                     size             = IVec3(16, 16, 1);
1348
1349         const VkFilter filters[2] =
1350         {
1351                 VK_FILTER_NEAREST,
1352                 VK_FILTER_LINEAR
1353         };
1354
1355         const VkSamplerMipmapMode mipmapFilters[2] =
1356         {
1357                 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1358                 VK_SAMPLER_MIPMAP_MODE_LINEAR,
1359         };
1360
1361         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
1362         {
1363                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
1364                 {
1365                         for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
1366                         {
1367                                 std::ostringstream caseName;
1368
1369                                 switch (filters[magFilterNdx])
1370                                 {
1371                                         case VK_FILTER_NEAREST:
1372                                                 caseName << "nearest";
1373                                                 break;
1374
1375                                         case VK_FILTER_LINEAR:
1376                                                 caseName << "linear";
1377                                                 break;
1378
1379                                         default:
1380                                                 break;
1381                                 }
1382
1383                                 switch (filters[minFilterNdx])
1384                                 {
1385                                         case VK_FILTER_NEAREST:
1386                                                 caseName << "_nearest";
1387                                                 break;
1388
1389                                         case VK_FILTER_LINEAR:
1390                                                 caseName << "_linear";
1391                                                 break;
1392
1393                                         default:
1394                                                 break;
1395                                 }
1396
1397                                 caseName << "_mipmap";
1398
1399                                 switch (mipmapFilters[mipmapFilterNdx])
1400                                 {
1401                                         case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1402                                                 caseName << "_nearest";
1403                                                 break;
1404
1405                                         case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1406                                                 caseName << "_linear";
1407                                                 break;
1408
1409                                         default:
1410                                                 break;
1411                                 }
1412
1413                                 Texture2DGradientTestCase* testCase =
1414                                         new Texture2DGradientTestCase(
1415                                                 testCtx,
1416                                                 caseName.str().c_str(),
1417                                                 "...",
1418                                                 mapVkFormat(format),
1419                                                 size,
1420                                                 filters[magFilterNdx],
1421                                                 filters[minFilterNdx],
1422                                                 mipmapFilters[mipmapFilterNdx],
1423                                                 wrappingMode,
1424                                                 true);
1425
1426                                 tests->addChild(testCase);
1427                         }
1428                 }
1429         }
1430
1431         return tests.release();
1432 }
1433
1434 TestCaseGroup* create2DSizeTests (TestContext& testCtx)
1435 {
1436         de::MovePtr<TestCaseGroup> tests(
1437                 new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations"));
1438
1439         const VkFilter filters[2] =
1440         {
1441                 VK_FILTER_NEAREST,
1442                 VK_FILTER_LINEAR
1443         };
1444
1445         const VkSamplerMipmapMode mipmapFilters[2] =
1446         {
1447                 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1448                 VK_SAMPLER_MIPMAP_MODE_LINEAR
1449         };
1450
1451         const VkSamplerAddressMode wrappingModes[2] =
1452         {
1453                 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1454                 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
1455         };
1456
1457         const IVec3 sizes[] =
1458         {
1459                 IVec3(2, 2, 1),
1460                 IVec3(2, 3, 1),
1461                 IVec3(3, 7, 1),
1462                 IVec3(4, 8, 1),
1463                 IVec3(31, 55, 1),
1464                 IVec3(32, 32, 1),
1465                 IVec3(32, 64, 1),
1466                 IVec3(57, 35, 1),
1467                 IVec3(128, 128, 1)
1468         };
1469
1470
1471         for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1472         {
1473                 for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx)
1474                 {
1475                         for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx)
1476                         {
1477                                 for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx)
1478                                 {
1479                                         for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx)
1480                                         {
1481                                                 std::ostringstream caseName;
1482
1483                                                 caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1];
1484
1485                                                 switch (filters[magFilterNdx])
1486                                                 {
1487                                                         case VK_FILTER_NEAREST:
1488                                                                 caseName << "_nearest";
1489                                                                 break;
1490
1491                                                         case VK_FILTER_LINEAR:
1492                                                                 caseName << "_linear";
1493                                                                 break;
1494
1495                                                         default:
1496                                                                 break;
1497                                                 }
1498
1499                                                 switch (filters[minFilterNdx])
1500                                                 {
1501                                                         case VK_FILTER_NEAREST:
1502                                                                 caseName << "_nearest";
1503                                                                 break;
1504
1505                                                         case VK_FILTER_LINEAR:
1506                                                                 caseName << "_linear";
1507                                                                 break;
1508
1509                                                         default:
1510                                                                 break;
1511                                                 }
1512
1513                                                 switch (mipmapFilters[mipmapFilterNdx])
1514                                                 {
1515                                                         case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1516                                                                 caseName << "_mipmap_nearest";
1517                                                                 break;
1518
1519                                                         case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1520                                                                 caseName << "_mipmap_linear";
1521                                                                 break;
1522
1523                                                         default:
1524                                                                 break;
1525                                                 }
1526
1527                                                 switch (wrappingModes[wrappingModeNdx])
1528                                                 {
1529                                                         case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1530                                                                 caseName << "_clamp";
1531                                                                 break;
1532
1533                                                         case VK_SAMPLER_ADDRESS_MODE_REPEAT:
1534                                                                 caseName << "_repeat";
1535                                                                 break;
1536
1537                                                         default:
1538                                                                 break;
1539                                                 }
1540
1541                                                 Texture2DGradientTestCase* testCase =
1542                                                         new Texture2DGradientTestCase(
1543                                                                 testCtx,
1544                                                                 caseName.str().c_str(),
1545                                                                 "...",
1546                                                                 mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM),
1547                                                                 sizes[sizeNdx],
1548                                                                 filters[magFilterNdx],
1549                                                                 filters[minFilterNdx],
1550                                                                 mipmapFilters[mipmapFilterNdx],
1551                                                                 wrappingModes[wrappingModeNdx],
1552                                                                 false);
1553
1554                                                 tests->addChild(testCase);
1555                                         }
1556                                 }
1557                         }
1558                 }
1559         }
1560
1561         return tests.release();
1562 }
1563
1564 TestCaseGroup* create2DTests (TestContext& testCtx)
1565 {
1566         de::MovePtr<TestCaseGroup> tests(
1567                 new TestCaseGroup(testCtx, "2d", "2D Image filtering tests"));
1568
1569         tests->addChild(create2DSizeTests(testCtx));
1570         tests->addChild(create2DFormatTests(testCtx));
1571         tests->addChild(create2DDerivTests(testCtx));
1572
1573         return tests.release();
1574 }
1575
1576 } // anonymous
1577
1578 TestCaseGroup* createExplicitLodTests (TestContext& testCtx)
1579 {
1580         de::MovePtr<TestCaseGroup> tests(
1581                 new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD"));
1582
1583         tests->addChild(create2DTests(testCtx));
1584
1585         return tests.release();
1586 }
1587
1588 } // texture
1589 } // vkt