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