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