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