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