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