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