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