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