Enable explicit_lod tests
[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, int fpPrecisionDelta)
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, std::max(0,channelDepth[channelIdx] + fpPrecisionDelta), false, tcu::YES));
86                                 break;
87
88                         case TEXTURECHANNELCLASS_FLOATING_POINT:
89                                 if (channelDepth[channelIdx] == 16)
90                                 {
91                                         floatFormats.push_back(tcu::FloatFormat(fp16.getMinExp(), fp16.getMaxExp(), std::max(0,fp16.getFractionBits() + fpPrecisionDelta), false, tcu::YES));
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         const tcu::TextureFormat                tcuFormat                       = mapVkFormat(m_imParams.format);
619         std::vector<tcu::FloatFormat>   strictPrecision         = getPrecision(m_imParams.format, 0);
620         std::vector<tcu::FloatFormat>   relaxedPrecision        = tcuFormat.type == tcu::TextureFormat::HALF_FLOAT ? getPrecision(m_imParams.format, -3) : getPrecision(m_imParams.format, -2);
621         const bool                                              allowRelaxedPrecision   = (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT || tcuFormat.type == tcu::TextureFormat::SNORM_INT8) &&
622                 (m_samplerParams.minFilter == VK_FILTER_LINEAR || m_samplerParams.magFilter == VK_FILTER_LINEAR);
623
624         const SampleVerifier                    verifier                        (m_imParams,
625                                                                                                                  m_samplerParams,
626                                                                                                                  m_sampleLookupSettings,
627                                                                                                                  coordBits,
628                                                                                                                  mipmapBits,
629                                                                                                                  strictPrecision,
630                                                                                                                  strictPrecision,
631                                                                                                                  m_levels);
632
633         const SampleVerifier                    relaxedVerifier         (m_imParams,
634                                                                                                                  m_samplerParams,
635                                                                                                                  m_sampleLookupSettings,
636                                                                                                                  coordBits,
637                                                                                                                  mipmapBits,
638                                                                                                                  strictPrecision,
639                                                                                                                  relaxedPrecision,
640                                                                                                                  m_levels);
641
642         for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
643         {
644                 bool compareOK = verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]);
645                 if (compareOK)
646                         continue;
647                 if (allowRelaxedPrecision)
648                 {
649                         m_context.getTestContext().getLog()
650                                 << tcu::TestLog::Message
651                                 << "Warning: Strict validation failed, re-trying with lower precision for SNORM8 format or half float"
652                                 << tcu::TestLog::EndMessage;
653
654                         compareOK = relaxedVerifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]);
655                         if (compareOK)
656                                 continue;
657                 }
658                 if ( failCount++ < maxPrintedFailures )
659                 {
660                         // Re-run with report logging
661                         std::string report;
662                         verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
663
664                         m_context.getTestContext().getLog()
665                                 << TestLog::Section("Failed sample", "Failed sample")
666                                 << TestLog::Message
667                                 << "Sample " << sampleNdx << ".\n"
668                                 << "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
669                                 << "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
670                                 << "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n"
671                                 << "Failure report:\n" << report << "\n"
672                                 << TestLog::EndMessage
673                                 << TestLog::EndSection;
674                 }
675         }
676
677         m_context.getTestContext().getLog()
678                 << TestLog::Message
679                 << "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
680                 << TestLog::EndMessage;
681
682         return failCount == 0;
683 }
684
685 void TextureFilteringTestInstance::execute (void)
686 {
687         std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods;
688
689         for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
690         {
691                 const SampleArguments& sampleArgs = m_sampleArguments[ndx];
692
693                 for (deUint8 compNdx = 0; compNdx < 4; ++compNdx)
694                 {
695                         coords.push_back(sampleArgs.coord[compNdx]);
696                         dPdxs .push_back(sampleArgs.dPdx[compNdx]);
697                         dPdys .push_back(sampleArgs.dPdy[compNdx]);
698                 }
699
700                 layers.push_back(sampleArgs.layer);
701                 dRefs .push_back(sampleArgs.dRef);
702                 lods  .push_back(sampleArgs.lod);
703         }
704
705         const void* inputs[6] =
706         {
707                 reinterpret_cast<const void*>(&coords[0]),
708                 reinterpret_cast<const void*>(&layers[0]),
709                 reinterpret_cast<const void*>(&dRefs[0]),
710                 reinterpret_cast<const void*>(&dPdxs[0]),
711                 reinterpret_cast<const void*>(&dPdys[0]),
712                 reinterpret_cast<const void*>(&lods[0])
713         };
714
715         // Staging buffers; data will be copied into vectors of Vec4
716         // \todo [2016-06-24 collinbaker] Figure out if I actually need to
717         // use staging buffers
718         std::vector<float> resultSamplesTemp(m_numSamples * 4);
719         std::vector<float> resultCoordsTemp (m_numSamples * 4);
720
721         void* outputs[2] =
722         {
723                 reinterpret_cast<void*>(&resultSamplesTemp[0]),
724                 reinterpret_cast<void*>(&resultCoordsTemp[0])
725         };
726
727         m_executor->execute(m_numSamples, inputs, outputs, *m_extraResourcesSet);
728
729         m_resultSamples.resize(m_numSamples);
730         m_resultCoords .resize(m_numSamples);
731
732         for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
733         {
734                 m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0],
735                                                                         resultSamplesTemp[4 * ndx + 1],
736                                                                         resultSamplesTemp[4 * ndx + 2],
737                                                                         resultSamplesTemp[4 * ndx + 3]);
738
739                 m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0],
740                                                                         resultCoordsTemp [4 * ndx + 1],
741                                                                         resultCoordsTemp [4 * ndx + 2],
742                                                                         resultCoordsTemp [4 * ndx + 3]);
743         }
744 }
745
746 void TextureFilteringTestInstance::createResources (void)
747 {
748         // Create VkImage
749
750         const DeviceInterface&          vkd                             = m_context.getDeviceInterface();
751         const VkDevice                          device                  = m_context.getDevice();
752
753         const deUint32                          queueFamily             = m_context.getUniversalQueueFamilyIndex();
754         const VkImageCreateFlags        imCreateFlags   =(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
755
756         const VkImageCreateInfo         imCreateInfo    =
757         {
758                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
759                 DE_NULL,
760                 imCreateFlags,
761             mapImageType(m_imParams.dim),
762             m_imParams.format,
763                 makeExtent3D(m_imParams.size[0], m_imParams.size[1], m_imParams.size[2]),
764             (deUint32)m_imParams.levels,
765             (deUint32)m_imParams.arrayLayers,
766                 VK_SAMPLE_COUNT_1_BIT,
767                 VK_IMAGE_TILING_OPTIMAL,
768                 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
769                 VK_SHARING_MODE_EXCLUSIVE,
770                 1,
771                 &queueFamily,
772                 VK_IMAGE_LAYOUT_UNDEFINED
773         };
774
775     m_im = createImage(vkd, device, &imCreateInfo);
776
777         // Allocate memory for image
778
779         VkMemoryRequirements imMemReq;
780         vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq);
781
782         m_imAllocation = m_context.getDefaultAllocator().allocate(imMemReq, MemoryRequirement::Any);
783         VK_CHECK(vkd.bindImageMemory(device, m_im.get(), m_imAllocation->getMemory(), m_imAllocation->getOffset()));
784
785         // Create VkImageView
786
787         // \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images)
788         DE_ASSERT(m_imParams.dim != IMG_DIM_CUBE); // \todo Support cube maps
789         const VkImageSubresourceRange imViewSubresourceRange =
790         {
791                 VK_IMAGE_ASPECT_COLOR_BIT,                      // aspectMask
792                 0,                                                                      // baseMipLevel
793                 (deUint32)m_imParams.levels,            // levelCount
794                 0,                                                                      // baseArrayLayer
795                 (deUint32)m_imParams.arrayLayers        // layerCount
796         };
797
798         const VkComponentMapping imViewCompMap =
799         {
800                 VK_COMPONENT_SWIZZLE_R,
801                 VK_COMPONENT_SWIZZLE_G,
802                 VK_COMPONENT_SWIZZLE_B,
803                 VK_COMPONENT_SWIZZLE_A
804         };
805
806         const VkImageViewCreateInfo imViewCreateInfo =
807         {
808                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,       // sType
809                 DE_NULL,                                                                        // pNext
810                 0,                                                                                      // flags
811                 m_im.get(),                                                                     // image
812                 mapImageViewType(m_imParams),                           // viewType
813             m_imParams.format,                                                  // format
814             imViewCompMap,                                                              // components
815                 imViewSubresourceRange                                          // subresourceRange
816         };
817
818         m_imView = createImageView(vkd, device, &imViewCreateInfo);
819
820         // Create VkSampler
821
822         const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams);
823         m_sampler = createSampler(vkd, device, &samplerCreateInfo);
824
825         // Create additional descriptors
826
827         {
828                 const VkDescriptorSetLayoutBinding              bindings[]      =
829                 {
830                         { 0u,   VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,      1u,             VK_SHADER_STAGE_ALL,    DE_NULL         },
831                 };
832                 const VkDescriptorSetLayoutCreateInfo   layoutInfo      =
833                 {
834                         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
835                         DE_NULL,
836                         (VkDescriptorSetLayoutCreateFlags)0u,
837                         DE_LENGTH_OF_ARRAY(bindings),
838                         bindings,
839                 };
840
841                 m_extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo);
842         }
843
844         {
845                 const VkDescriptorPoolSize                      poolSizes[]     =
846                 {
847                         { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,    1u      },
848                 };
849                 const VkDescriptorPoolCreateInfo        poolInfo        =
850                 {
851                         VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
852                         DE_NULL,
853                         (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
854                         1u,             // maxSets
855                         DE_LENGTH_OF_ARRAY(poolSizes),
856                         poolSizes,
857                 };
858
859                 m_extraResourcesPool = createDescriptorPool(vkd, device, &poolInfo);
860         }
861
862         {
863                 const VkDescriptorSetAllocateInfo       allocInfo       =
864                 {
865                         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
866                         DE_NULL,
867                         *m_extraResourcesPool,
868                         1u,
869                         &m_extraResourcesLayout.get(),
870                 };
871
872                 m_extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo);
873         }
874
875         {
876                 const VkDescriptorImageInfo             imageInfo                       =
877                 {
878                         *m_sampler,
879                         *m_imView,
880                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
881                 };
882                 const VkWriteDescriptorSet              descriptorWrite         =
883                 {
884                         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
885                         DE_NULL,
886                         *m_extraResourcesSet,
887                         0u,             // dstBinding
888                         0u,             // dstArrayElement
889                         1u,
890                         VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
891                         &imageInfo,
892                         (const VkDescriptorBufferInfo*)DE_NULL,
893                         (const VkBufferView*)DE_NULL,
894                 };
895
896                 vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
897         }
898
899         m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_context, m_shaderType, m_shaderSpec, *m_extraResourcesLayout));
900 }
901
902 VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams)
903 {
904         VkFormatFeatureFlags    features        = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
905
906         if (samplerParams.minFilter      == VK_FILTER_LINEAR ||
907                 samplerParams.magFilter  == VK_FILTER_LINEAR ||
908                 samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
909         {
910                 features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
911         }
912
913         return features;
914 }
915
916 bool TextureFilteringTestInstance::isSupported (void)
917 {
918         const VkImageCreateFlags                imCreateFlags           = (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
919         const VkFormatFeatureFlags              reqImFeatures           = getRequiredFormatFeatures(m_samplerParams);
920
921         const VkImageFormatProperties   imFormatProperties      = getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(),
922                                                                                                                                                                                                  m_context.getPhysicalDevice(),
923                                                                                                                                                                                                  m_imParams.format,
924                                                                                                                                                                                                  mapImageType(m_imParams.dim),
925                                                                                                                                                                                                  VK_IMAGE_TILING_OPTIMAL,
926                                                                                                                                                                                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
927                                                                                                                                                                                                  imCreateFlags);
928         const VkFormatProperties                formatProperties        = getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(),
929                                                                                                                                                                                         m_context.getPhysicalDevice(),
930                                                                                                                                                                                         m_imParams.format);
931
932         // \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties
933         DE_UNREF(imFormatProperties);
934
935         return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures;
936 }
937
938 class TextureFilteringTestCase : public TestCase
939 {
940 public:
941         TextureFilteringTestCase (tcu::TestContext&     testCtx,
942                                                           const char*           name,
943                                                           const char*           description)
944                 : TestCase(testCtx, name, description)
945         {
946         }
947
948         void initSpec (void);
949
950         virtual void initPrograms (vk::SourceCollections& programCollection) const
951         {
952                 generateSources(m_testCaseData.shaderType, m_shaderSpec, programCollection);
953         }
954
955         virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0;
956
957         virtual TestInstance* createInstance (Context& ctx) const
958         {
959                 return new TextureFilteringTestInstance(ctx, m_testCaseData, m_shaderSpec, createGenerator());
960         }
961
962 protected:
963         de::MovePtr<ShaderExecutor> m_executor;
964         TestCaseData                            m_testCaseData;
965         ShaderSpec                                      m_shaderSpec;
966 };
967
968 void TextureFilteringTestCase::initSpec (void)
969 {
970         m_shaderSpec.source = genLookupCode(m_testCaseData.imParams,
971                                                                                 m_testCaseData.samplerParams,
972                                                                                 m_testCaseData.sampleLookupSettings);
973         m_shaderSpec.source += "\nsampledCoord = coord;";
974
975         m_shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
976         m_shaderSpec.outputs.push_back(Symbol("sampledCoord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
977         m_shaderSpec.inputs .push_back(Symbol("coord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
978         m_shaderSpec.inputs .push_back(Symbol("layer", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
979         m_shaderSpec.inputs .push_back(Symbol("dRef", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
980         m_shaderSpec.inputs .push_back(Symbol("dPdx", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
981         m_shaderSpec.inputs .push_back(Symbol("dPdy", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
982         m_shaderSpec.inputs .push_back(Symbol("lod", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
983
984         m_shaderSpec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp ";
985         m_shaderSpec.globalDeclarations += genSamplerDeclaration(m_testCaseData.imParams,
986                                                                                                                    m_testCaseData.samplerParams);
987         m_shaderSpec.globalDeclarations += " testSampler;";
988 }
989
990 class Texture2DGradientTestCase : public TextureFilteringTestCase
991 {
992 public:
993         Texture2DGradientTestCase (TestContext&                 testCtx,
994                                                            const char*                  name,
995                                                            const char*                  desc,
996                                                            TextureFormat                format,
997                                                            IVec3                                dimensions,
998                                                            VkFilter                             magFilter,
999                                                            VkFilter                             minFilter,
1000                                                            VkSamplerMipmapMode  mipmapFilter,
1001                                                            VkSamplerAddressMode wrappingMode,
1002                                                            bool                                 useDerivatives)
1003
1004                 : TextureFilteringTestCase      (testCtx, name, desc)
1005                 , m_format                                      (format)
1006                 , m_dimensions                          (dimensions)
1007                 , m_magFilter                           (magFilter)
1008                 , m_minFilter                           (minFilter)
1009                 , m_mipmapFilter                        (mipmapFilter)
1010                 , m_wrappingMode                        (wrappingMode)
1011                 , m_useDerivatives                      (useDerivatives)
1012         {
1013                 m_testCaseData = genTestCaseData();
1014                 initSpec();
1015         }
1016
1017 protected:
1018         class Generator;
1019
1020         virtual de::MovePtr<DataGenerator> createGenerator (void) const;
1021
1022         TestCaseData genTestCaseData()
1023         {
1024                 // Generate grid
1025
1026                 const SampleLookupSettings sampleLookupSettings =
1027                 {
1028                         m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
1029                         false, // hasLodBias
1030                         false, // isProjective
1031                 };
1032
1033                 const SamplerParameters samplerParameters =
1034                 {
1035                         m_magFilter,
1036                         m_minFilter,
1037                         m_mipmapFilter,
1038                         m_wrappingMode,
1039                         m_wrappingMode,
1040                         m_wrappingMode,
1041                         VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1042                         0.0f,
1043                         -1.0f,
1044                         50.0f,
1045                         false,
1046                         false
1047                 };
1048
1049                 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0],
1050                                                                                                                                            m_dimensions[1])));
1051
1052                 const ImageViewParameters imParameters =
1053                 {
1054                         IMG_DIM_2D,
1055                         mapTextureFormat(m_format),
1056                         m_dimensions,
1057                         numLevels,
1058                         false,
1059                         1,
1060                 };
1061
1062                 const TestCaseData data =
1063                 {
1064                         std::vector<ConstPixelBufferAccess>(),
1065                         imParameters,
1066                         samplerParameters,
1067                         sampleLookupSettings,
1068                         glu::SHADERTYPE_FRAGMENT
1069                 };
1070
1071                 return data;
1072         }
1073
1074 private:
1075         const TextureFormat                     m_format;
1076         const IVec3                                     m_dimensions;
1077         const VkFilter                          m_magFilter;
1078         const VkFilter                          m_minFilter;
1079         const VkSamplerMipmapMode       m_mipmapFilter;
1080         const VkSamplerAddressMode      m_wrappingMode;
1081         const bool                                      m_useDerivatives;
1082 };
1083
1084 class Texture2DGradientTestCase::Generator : public DataGenerator
1085 {
1086 public:
1087         Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {}
1088
1089         virtual ~Generator (void)
1090         {
1091                 delete m_tex.release();
1092         }
1093
1094         virtual bool generate (void)
1095         {
1096                 m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format,
1097                                                                                                          m_testCase->m_dimensions[0],
1098                                                                                                          m_testCase->m_dimensions[1]));
1099
1100                 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0],
1101                                                                                                                                            m_testCase->m_dimensions[1])));
1102
1103                 const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format);
1104
1105                 const Vec4 cBias  = fmtInfo.valueMin;
1106                 const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
1107
1108                 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1109                 {
1110                         const Vec4 gMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
1111                         const Vec4 gMax = Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
1112
1113                         m_tex->allocLevel(levelNdx);
1114                         fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax);
1115                 }
1116
1117                 return true;
1118         }
1119
1120         virtual std::vector<ConstPixelBufferAccess> getPba (void) const
1121         {
1122                 std::vector<ConstPixelBufferAccess> pba;
1123
1124                 const deUint8 numLevels = (deUint8) m_tex->getNumLevels();
1125
1126                 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1127                 {
1128                         pba.push_back(m_tex->getLevel(levelNdx));
1129                 }
1130
1131                 return pba;
1132         }
1133
1134         virtual std::vector<SampleArguments> getSampleArgs (void) const
1135         {
1136                 std::vector<SampleArguments> args;
1137
1138                 if (m_testCase->m_useDerivatives)
1139                 {
1140                         struct
1141                         {
1142                                 Vec4 dPdx;
1143                                 Vec4 dPdy;
1144                         }
1145                         derivativePairs[] =
1146                         {
1147                                 {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1148                                 {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1149                                 {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1150                                 {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1151                                 {Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)}
1152                         };
1153
1154                         for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1155                         {
1156                                 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1157                                 {
1158                                     for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
1159                                         {
1160                                                 SampleArguments cur = SampleArguments();
1161                                                 cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1162                                                                                  (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1163                                                                                  0.0f, 0.0f);
1164                                                 cur.dPdx = derivativePairs[derivNdx].dPdx;
1165                                                 cur.dPdy = derivativePairs[derivNdx].dPdy;
1166
1167                                                 args.push_back(cur);
1168                                         }
1169                                 }
1170                         }
1171                 }
1172                 else
1173                 {
1174                         const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
1175
1176                         for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1177                         {
1178                                 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1179                                 {
1180                                         for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
1181                                         {
1182                                                 SampleArguments cur = SampleArguments();
1183                                                 cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1184                                                                                  (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1185                                                                                  0.0f, 0.0f);
1186                                                 cur.lod = lodList[lodNdx];
1187
1188                                                 args.push_back(cur);
1189                                         }
1190                                 }
1191                         }
1192                 }
1193
1194                 return args;
1195         }
1196
1197 private:
1198         const Texture2DGradientTestCase*        m_testCase;
1199         de::MovePtr<Texture2D>                          m_tex;
1200 };
1201
1202 de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const
1203 {
1204         return de::MovePtr<DataGenerator>(new Generator(this));
1205 }
1206
1207 TestCaseGroup* create2DFormatTests (TestContext& testCtx)
1208 {
1209         de::MovePtr<TestCaseGroup> tests(
1210                 new TestCaseGroup(testCtx, "formats", "Various image formats"));
1211
1212     const VkFormat formats[] =
1213         {
1214             VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1215                 VK_FORMAT_R5G6B5_UNORM_PACK16,
1216                 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1217                 VK_FORMAT_R8_UNORM,
1218                 VK_FORMAT_R8_SNORM,
1219                 VK_FORMAT_R8G8_UNORM,
1220                 VK_FORMAT_R8G8_SNORM,
1221                 VK_FORMAT_R8G8B8A8_UNORM,
1222                 VK_FORMAT_R8G8B8A8_SNORM,
1223 //              VK_FORMAT_R8G8B8A8_SRGB,
1224                 VK_FORMAT_B8G8R8A8_UNORM,
1225 //              VK_FORMAT_B8G8R8A8_SRGB,
1226                 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1227                 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1228 //              VK_FORMAT_A8B8G8R8_SRGB_PACK32,
1229                 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1230                 VK_FORMAT_R16_SFLOAT,
1231                 VK_FORMAT_R16G16_SFLOAT,
1232                 VK_FORMAT_R16G16B16A16_SFLOAT,
1233                 VK_FORMAT_R32_SFLOAT,
1234                 VK_FORMAT_R32G32_SFLOAT,
1235                 VK_FORMAT_R32G32B32A32_SFLOAT,
1236 //              VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1237 //              VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
1238         };
1239
1240         const IVec3 size(32, 32, 1);
1241
1242         for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
1243         {
1244                 const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
1245
1246                 Texture2DGradientTestCase* testCaseNearest =
1247                         new Texture2DGradientTestCase(
1248                                 testCtx,
1249                             (prefix + "_nearest").c_str(),
1250                                 "...",
1251                                 mapVkFormat(formats[formatNdx]),
1252                                 size,
1253                                 VK_FILTER_NEAREST,
1254                                 VK_FILTER_NEAREST,
1255                                 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1256                                 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1257                                 false);
1258
1259                 tests->addChild(testCaseNearest);
1260
1261             Texture2DGradientTestCase* testCaseLinear =
1262                         new Texture2DGradientTestCase(
1263                                 testCtx,
1264                             (prefix + "_linear").c_str(),
1265                                 "...",
1266                                 mapVkFormat(formats[formatNdx]),
1267                                 size,
1268                                 VK_FILTER_LINEAR,
1269                                 VK_FILTER_LINEAR,
1270                                 VK_SAMPLER_MIPMAP_MODE_LINEAR,
1271                                 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1272                                 false);
1273
1274                 tests->addChild(testCaseLinear);
1275         }
1276
1277         return tests.release();
1278 }
1279
1280 TestCaseGroup* create2DDerivTests (TestContext& testCtx)
1281 {
1282         de::MovePtr<TestCaseGroup> tests(
1283                 new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
1284
1285         const VkFormat                          format           = VK_FORMAT_R8G8B8A8_UNORM;
1286         const VkSamplerAddressMode      wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1287         const IVec3                                     size             = IVec3(16, 16, 1);
1288
1289         const VkFilter filters[2] =
1290         {
1291                 VK_FILTER_NEAREST,
1292                 VK_FILTER_LINEAR
1293         };
1294
1295         const VkSamplerMipmapMode mipmapFilters[2] =
1296         {
1297                 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1298                 VK_SAMPLER_MIPMAP_MODE_LINEAR,
1299         };
1300
1301         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
1302         {
1303                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
1304                 {
1305                         for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
1306                         {
1307                                 std::ostringstream caseName;
1308
1309                                 switch (filters[magFilterNdx])
1310                                 {
1311                                         case VK_FILTER_NEAREST:
1312                                                 caseName << "nearest";
1313                                                 break;
1314
1315                                         case VK_FILTER_LINEAR:
1316                                                 caseName << "linear";
1317                                                 break;
1318
1319                                         default:
1320                                                 break;
1321                                 }
1322
1323                                 switch (filters[minFilterNdx])
1324                                 {
1325                                         case VK_FILTER_NEAREST:
1326                                                 caseName << "_nearest";
1327                                                 break;
1328
1329                                         case VK_FILTER_LINEAR:
1330                                                 caseName << "_linear";
1331                                                 break;
1332
1333                                         default:
1334                                                 break;
1335                                 }
1336
1337                                 caseName << "_mipmap";
1338
1339                                 switch (mipmapFilters[mipmapFilterNdx])
1340                                 {
1341                                         case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1342                                                 caseName << "_nearest";
1343                                                 break;
1344
1345                                         case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1346                                                 caseName << "_linear";
1347                                                 break;
1348
1349                                         default:
1350                                                 break;
1351                                 }
1352
1353                                 Texture2DGradientTestCase* testCase =
1354                                         new Texture2DGradientTestCase(
1355                                                 testCtx,
1356                                                 caseName.str().c_str(),
1357                                                 "...",
1358                                                 mapVkFormat(format),
1359                                                 size,
1360                                                 filters[magFilterNdx],
1361                                                 filters[minFilterNdx],
1362                                                 mipmapFilters[mipmapFilterNdx],
1363                                                 wrappingMode,
1364                                                 true);
1365
1366                                 tests->addChild(testCase);
1367                         }
1368                 }
1369         }
1370
1371         return tests.release();
1372 }
1373
1374 TestCaseGroup* create2DSizeTests (TestContext& testCtx)
1375 {
1376         de::MovePtr<TestCaseGroup> tests(
1377                 new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations"));
1378
1379         const VkFilter filters[2] =
1380         {
1381                 VK_FILTER_NEAREST,
1382                 VK_FILTER_LINEAR
1383         };
1384
1385         const VkSamplerMipmapMode mipmapFilters[2] =
1386         {
1387                 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1388                 VK_SAMPLER_MIPMAP_MODE_LINEAR
1389         };
1390
1391         const VkSamplerAddressMode wrappingModes[2] =
1392         {
1393                 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1394                 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
1395         };
1396
1397         const IVec3 sizes[] =
1398         {
1399                 IVec3(2, 2, 1),
1400                 IVec3(2, 3, 1),
1401                 IVec3(3, 7, 1),
1402                 IVec3(4, 8, 1),
1403                 IVec3(31, 55, 1),
1404                 IVec3(32, 32, 1),
1405                 IVec3(32, 64, 1),
1406                 IVec3(57, 35, 1),
1407                 IVec3(128, 128, 1)
1408         };
1409
1410
1411         for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1412         {
1413                 for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx)
1414                 {
1415                         for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx)
1416                         {
1417                                 for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx)
1418                                 {
1419                                         for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx)
1420                                         {
1421                                                 std::ostringstream caseName;
1422
1423                                                 caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1];
1424
1425                                                 switch (filters[magFilterNdx])
1426                                                 {
1427                                                         case VK_FILTER_NEAREST:
1428                                                                 caseName << "_nearest";
1429                                                                 break;
1430
1431                                                         case VK_FILTER_LINEAR:
1432                                                                 caseName << "_linear";
1433                                                                 break;
1434
1435                                                         default:
1436                                                                 break;
1437                                                 }
1438
1439                                                 switch (filters[minFilterNdx])
1440                                                 {
1441                                                         case VK_FILTER_NEAREST:
1442                                                                 caseName << "_nearest";
1443                                                                 break;
1444
1445                                                         case VK_FILTER_LINEAR:
1446                                                                 caseName << "_linear";
1447                                                                 break;
1448
1449                                                         default:
1450                                                                 break;
1451                                                 }
1452
1453                                                 switch (mipmapFilters[mipmapFilterNdx])
1454                                                 {
1455                                                         case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1456                                                                 caseName << "_mipmap_nearest";
1457                                                                 break;
1458
1459                                                         case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1460                                                                 caseName << "_mipmap_linear";
1461                                                                 break;
1462
1463                                                         default:
1464                                                                 break;
1465                                                 }
1466
1467                                                 switch (wrappingModes[wrappingModeNdx])
1468                                                 {
1469                                                         case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1470                                                                 caseName << "_clamp";
1471                                                                 break;
1472
1473                                                         case VK_SAMPLER_ADDRESS_MODE_REPEAT:
1474                                                                 caseName << "_repeat";
1475                                                                 break;
1476
1477                                                         default:
1478                                                                 break;
1479                                                 }
1480
1481                                                 Texture2DGradientTestCase* testCase =
1482                                                         new Texture2DGradientTestCase(
1483                                                                 testCtx,
1484                                                                 caseName.str().c_str(),
1485                                                                 "...",
1486                                                                 mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM),
1487                                                                 sizes[sizeNdx],
1488                                                                 filters[magFilterNdx],
1489                                                                 filters[minFilterNdx],
1490                                                                 mipmapFilters[mipmapFilterNdx],
1491                                                                 wrappingModes[wrappingModeNdx],
1492                                                                 false);
1493
1494                                                 tests->addChild(testCase);
1495                                         }
1496                                 }
1497                         }
1498                 }
1499         }
1500
1501         return tests.release();
1502 }
1503
1504 TestCaseGroup* create2DTests (TestContext& testCtx)
1505 {
1506         de::MovePtr<TestCaseGroup> tests(
1507                 new TestCaseGroup(testCtx, "2d", "2D Image filtering tests"));
1508
1509         tests->addChild(create2DSizeTests(testCtx));
1510         tests->addChild(create2DFormatTests(testCtx));
1511         tests->addChild(create2DDerivTests(testCtx));
1512
1513         return tests.release();
1514 }
1515
1516 } // anonymous
1517
1518 TestCaseGroup* createExplicitLodTests (TestContext& testCtx)
1519 {
1520         de::MovePtr<TestCaseGroup> tests(
1521                 new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD"));
1522
1523         tests->addChild(create2DTests(testCtx));
1524
1525         return tests.release();
1526 }
1527
1528 } // texture
1529 } // vkt