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