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