1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 Google Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Texture filtering tests with explicit LOD instructions
22 *//*--------------------------------------------------------------------*/
24 #include "vktTextureFilteringExplicitLodTests.hpp"
28 #include "vktSampleVerifier.hpp"
29 #include "vktShaderExecutor.hpp"
30 #include "vktTestCaseUtil.hpp"
32 #include "vkDeviceUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkPlatform.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"
43 #include "tcuTexLookupVerifier.hpp"
44 #include "tcuTestLog.hpp"
45 #include "tcuTexture.hpp"
46 #include "tcuTextureUtil.hpp"
47 #include "tcuVector.hpp"
51 #include "deStringUtil.hpp"
52 #include "deUniquePtr.hpp"
53 #include "deSharedPtr.hpp"
71 std::vector<de::SharedPtr<tcu::FloatFormat>> getPrecision (VkFormat format, int fpPrecisionDelta)
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);
80 for (int channelIdx = 0; channelIdx < 4; channelIdx++)
84 case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
85 floatFormats.push_back(de::SharedPtr<tcu::FloatFormat>(new tcu::NormalizedFormat(std::max(0,channelDepth[channelIdx] + fpPrecisionDelta - 1))));
88 case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
89 floatFormats.push_back(de::SharedPtr<tcu::FloatFormat>(new tcu::NormalizedFormat(std::max(0,channelDepth[channelIdx] + fpPrecisionDelta))));
92 case TEXTURECHANNELCLASS_FLOATING_POINT:
93 if (channelDepth[channelIdx] == 16)
95 floatFormats.push_back(fp16);
99 DE_ASSERT(channelDepth[channelIdx] == 32 || channelDepth[channelIdx] == 0);
100 floatFormats.push_back(fp32);
105 DE_FATAL("Unexpected channel class.");
113 using namespace shaderexecutor;
115 string genSamplerDeclaration(const ImageViewParameters& imParams,
116 const SamplerParameters& samplerParams)
118 string result = "sampler";
120 switch (imParams.dim)
142 if (imParams.isArrayed)
147 if (samplerParams.isCompare)
155 string genLookupCode(const ImageViewParameters& imParams,
156 const SamplerParameters& samplerParams,
157 const SampleLookupSettings& lookupSettings)
161 switch (imParams.dim)
184 DE_ASSERT(dim >= 1 && dim <= 3);
186 int numCoordComp = dim;
188 if (lookupSettings.isProjective)
193 int numArgComp = numCoordComp;
194 bool hasSeparateCompare = false;
196 if (imParams.isArrayed)
198 DE_ASSERT(!lookupSettings.isProjective && "Can't do a projective lookup on an arrayed image!");
203 if (samplerParams.isCompare && numCoordComp == 4)
205 hasSeparateCompare = true;
207 else if (samplerParams.isCompare)
212 // Build coordinate input to texture*() function
215 arg += (char) (numArgComp + '0');
217 arg += (char) (numCoordComp + '0');
220 int numZero = numArgComp - numCoordComp;
222 if (imParams.isArrayed)
228 if (samplerParams.isCompare && !hasSeparateCompare)
234 for (int ndx = 0; ndx < numZero; ++ndx)
241 // Build call to texture*() function
245 code += "result = texture";
247 if (lookupSettings.isProjective)
252 if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
256 else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
261 code += "(testSampler, ";
264 if (samplerParams.isCompare && hasSeparateCompare)
269 if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
272 code += (char) (numCoordComp + '0');
275 code += (char) (numCoordComp + '0');
278 else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
288 void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba, ImageViewParameters imParams)
290 const DeviceInterface& vkd = ctx.getDeviceInterface();
291 const VkDevice dev = ctx.getDevice();
292 const deUint32 uqfi = ctx.getUniversalQueueFamilyIndex();
294 const VkDeviceSize bufSize =
295 getPixelSize(mapVkFormat(imParams.format))
296 * imParams.arrayLayers
302 const VkBufferCreateInfo bufCreateInfo =
304 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
308 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // usage
309 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
310 1, // queueFamilyIndexCount
311 &uqfi // pQueueFamilyIndices
314 Unique<VkBuffer> buf(createBuffer(vkd, dev, &bufCreateInfo));
316 VkMemoryRequirements bufMemReq;
317 vkd.getBufferMemoryRequirements(dev, buf.get(), &bufMemReq);
319 de::UniquePtr<Allocation> bufMem(ctx.getDefaultAllocator().allocate(bufMemReq, MemoryRequirement::HostVisible));
320 VK_CHECK(vkd.bindBufferMemory(dev, buf.get(), bufMem->getMemory(), bufMem->getOffset()));
322 std::vector<VkBufferImageCopy> copyRegions;
324 deUint8* const bufMapPtr = reinterpret_cast<deUint8*>(bufMem->getHostPtr());
325 deUint8* bufCurPtr = bufMapPtr;
327 for (int level = 0; level < imParams.levels; ++level)
329 const IVec3 curLevelSize = pba[level].getSize();
331 const std::size_t copySize =
332 getPixelSize(mapVkFormat(imParams.format))
333 * curLevelSize[0] * curLevelSize[1] * curLevelSize[2]
334 * imParams.arrayLayers;
336 deMemcpy(bufCurPtr, pba[level].getDataPtr(), copySize);
338 const VkImageSubresourceLayers curSubresource =
340 VK_IMAGE_ASPECT_COLOR_BIT,
343 (deUint32)imParams.arrayLayers
346 const VkBufferImageCopy curRegion =
348 (VkDeviceSize) (bufCurPtr - bufMapPtr),
353 {(deUint32)curLevelSize[0], (deUint32)curLevelSize[1], (deUint32)curLevelSize[2]}
356 copyRegions.push_back(curRegion);
358 bufCurPtr += copySize;
361 flushAlloc(vkd, dev, *bufMem);
363 copyBufferToImage(vkd, dev, ctx.getUniversalQueue(), ctx.getUniversalQueueFamilyIndex(), buf.get(), bufSize, copyRegions, DE_NULL, VK_IMAGE_ASPECT_COLOR_BIT, imParams.levels, imParams.arrayLayers, im);
368 std::vector<ConstPixelBufferAccess> pba;
369 ImageViewParameters imParams;
370 SamplerParameters samplerParams;
371 SampleLookupSettings sampleLookupSettings;
372 glu::ShaderType shaderType;
375 VkSamplerCreateInfo mapSamplerCreateInfo (const SamplerParameters& samplerParams)
377 VkSamplerCreateInfo samplerCreateInfo =
379 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // sType
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
399 if (samplerParams.isCompare)
401 samplerCreateInfo.compareEnable = VK_TRUE;
403 DE_FATAL("Not implemented");
406 return samplerCreateInfo;
409 VkImageType mapImageType (ImgDim dim)
416 imType = VK_IMAGE_TYPE_1D;
421 imType = VK_IMAGE_TYPE_2D;
425 imType = VK_IMAGE_TYPE_3D;
429 imType = VK_IMAGE_TYPE_LAST;
436 VkImageViewType mapImageViewType (const ImageViewParameters& imParams)
438 VkImageViewType imViewType;
440 if (imParams.isArrayed)
442 switch (imParams.dim)
445 imViewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
449 imViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
453 imViewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
457 imViewType = VK_IMAGE_VIEW_TYPE_LAST;
463 switch (imParams.dim)
466 imViewType = VK_IMAGE_VIEW_TYPE_1D;
470 imViewType = VK_IMAGE_VIEW_TYPE_2D;
474 imViewType = VK_IMAGE_VIEW_TYPE_3D;
478 imViewType = VK_IMAGE_VIEW_TYPE_CUBE;
482 imViewType = VK_IMAGE_VIEW_TYPE_LAST;
493 virtual ~DataGenerator (void) {}
495 virtual bool generate (void) = 0;
497 virtual std::vector<ConstPixelBufferAccess> getPba (void) const = 0;
498 virtual std::vector<SampleArguments> getSampleArgs (void) const = 0;
501 DataGenerator (void) {}
504 class TextureFilteringTestInstance : public TestInstance
507 TextureFilteringTestInstance (Context& ctx,
508 const TestCaseData& testCaseData,
509 const ShaderSpec& shaderSpec,
510 de::MovePtr<DataGenerator> gen);
512 virtual TestStatus iterate (void) { return runTest(); }
515 TestStatus runTest (void);
516 bool isSupported (void);
517 void createResources (void);
519 TestStatus verify (void);
521 tcu::Sampler mapTcuSampler (void) const;
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;
529 std::vector<SampleArguments> m_sampleArguments;
530 deUint32 m_numSamples;
532 de::MovePtr<Allocation> m_imAllocation;
534 Move<VkImageView> m_imView;
535 Move<VkSampler> m_sampler;
537 Move<VkDescriptorSetLayout> m_extraResourcesLayout;
538 Move<VkDescriptorPool> m_extraResourcesPool;
539 Move<VkDescriptorSet> m_extraResourcesSet;
541 de::MovePtr<ShaderExecutor> m_executor;
543 std::vector<ConstPixelBufferAccess> m_levels;
544 de::MovePtr<DataGenerator> m_gen;
546 std::vector<Vec4> m_resultSamples;
547 std::vector<Vec4> m_resultCoords;
550 TextureFilteringTestInstance::TextureFilteringTestInstance (Context& ctx,
551 const TestCaseData& testCaseData,
552 const ShaderSpec& shaderSpec,
553 de::MovePtr<DataGenerator> gen)
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())
563 for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
564 DE_ASSERT(m_imParams.size[compNdx] > 0);
567 TestStatus TextureFilteringTestInstance::runTest (void)
570 TCU_THROW(NotSupportedError, "Unsupported combination of filtering and image format");
572 TCU_CHECK(m_gen->generate());
573 m_levels = m_gen->getPba();
575 m_sampleArguments = m_gen->getSampleArgs();
576 m_numSamples = (deUint32)m_sampleArguments.size();
579 initializeImage(m_context, m_im.get(), &m_levels[0], m_imParams);
581 deUint64 startTime, endTime;
583 startTime = deGetMicroseconds();
585 endTime = deGetMicroseconds();
587 m_context.getTestContext().getLog() << TestLog::Message
588 << "Execution time: "
589 << endTime - startTime
591 << TestLog::EndMessage;
593 startTime = deGetMicroseconds();
594 TestStatus result = verify();
595 endTime = deGetMicroseconds();
597 m_context.getTestContext().getLog() << TestLog::Message
598 << "Verification time: "
599 << endTime - startTime
601 << TestLog::EndMessage;
606 TestStatus TextureFilteringTestInstance::verify (void)
608 // \todo [2016-06-24 collinbaker] Handle cubemaps
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;
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);
621 const SampleVerifier verifier (m_imParams,
623 m_sampleLookupSettings,
630 const SampleVerifier relaxedVerifier (m_imParams,
632 m_sampleLookupSettings,
639 for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
641 bool compareOK = verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]);
644 if (allowRelaxedPrecision)
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;
651 compareOK = relaxedVerifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]);
658 if ( failCount++ < maxPrintedFailures )
660 // Re-run with report logging
662 verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
664 m_context.getTestContext().getLog()
665 << TestLog::Section("Failed sample", "Failed sample")
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;
677 m_context.getTestContext().getLog()
679 << "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
680 << TestLog::EndMessage;
683 return TestStatus::fail("Verification failed");
684 else if (warningCount > 0)
685 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Inaccurate filtering results");
687 return TestStatus::pass("Success");
690 void TextureFilteringTestInstance::execute (void)
692 std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods;
694 for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
696 const SampleArguments& sampleArgs = m_sampleArguments[ndx];
698 for (deUint8 compNdx = 0; compNdx < 4; ++compNdx)
700 coords.push_back(sampleArgs.coord[compNdx]);
701 dPdxs .push_back(sampleArgs.dPdx[compNdx]);
702 dPdys .push_back(sampleArgs.dPdy[compNdx]);
705 layers.push_back(sampleArgs.layer);
706 dRefs .push_back(sampleArgs.dRef);
707 lods .push_back(sampleArgs.lod);
710 const void* inputs[6] =
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])
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);
728 reinterpret_cast<void*>(&resultSamplesTemp[0]),
729 reinterpret_cast<void*>(&resultCoordsTemp[0])
732 m_executor->execute(m_numSamples, inputs, outputs, *m_extraResourcesSet);
734 m_resultSamples.resize(m_numSamples);
735 m_resultCoords .resize(m_numSamples);
737 for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
739 m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0],
740 resultSamplesTemp[4 * ndx + 1],
741 resultSamplesTemp[4 * ndx + 2],
742 resultSamplesTemp[4 * ndx + 3]);
744 m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0],
745 resultCoordsTemp [4 * ndx + 1],
746 resultCoordsTemp [4 * ndx + 2],
747 resultCoordsTemp [4 * ndx + 3]);
751 void TextureFilteringTestInstance::createResources (void)
755 const DeviceInterface& vkd = m_context.getDeviceInterface();
756 const VkDevice device = m_context.getDevice();
758 const deUint32 queueFamily = m_context.getUniversalQueueFamilyIndex();
759 const VkImageCreateFlags imCreateFlags =(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
761 const VkImageCreateInfo imCreateInfo =
763 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
766 mapImageType(m_imParams.dim),
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,
777 VK_IMAGE_LAYOUT_UNDEFINED
780 m_im = createImage(vkd, device, &imCreateInfo);
782 // Allocate memory for image
784 VkMemoryRequirements imMemReq;
785 vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq);
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()));
790 // Create VkImageView
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 =
796 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
798 (deUint32)m_imParams.levels, // levelCount
800 (deUint32)m_imParams.arrayLayers // layerCount
803 const VkComponentMapping imViewCompMap =
805 VK_COMPONENT_SWIZZLE_R,
806 VK_COMPONENT_SWIZZLE_G,
807 VK_COMPONENT_SWIZZLE_B,
808 VK_COMPONENT_SWIZZLE_A
811 const VkImageViewCreateInfo imViewCreateInfo =
813 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
817 mapImageViewType(m_imParams), // viewType
818 m_imParams.format, // format
819 imViewCompMap, // components
820 imViewSubresourceRange // subresourceRange
823 m_imView = createImageView(vkd, device, &imViewCreateInfo);
827 const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams);
828 m_sampler = createSampler(vkd, device, &samplerCreateInfo);
830 // Create additional descriptors
833 const VkDescriptorSetLayoutBinding bindings[] =
835 { 0u, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u, VK_SHADER_STAGE_ALL, DE_NULL },
837 const VkDescriptorSetLayoutCreateInfo layoutInfo =
839 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
841 (VkDescriptorSetLayoutCreateFlags)0u,
842 DE_LENGTH_OF_ARRAY(bindings),
846 m_extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo);
850 const VkDescriptorPoolSize poolSizes[] =
852 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u },
854 const VkDescriptorPoolCreateInfo poolInfo =
856 VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
858 (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
860 DE_LENGTH_OF_ARRAY(poolSizes),
864 m_extraResourcesPool = createDescriptorPool(vkd, device, &poolInfo);
868 const VkDescriptorSetAllocateInfo allocInfo =
870 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
872 *m_extraResourcesPool,
874 &m_extraResourcesLayout.get(),
877 m_extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo);
881 const VkDescriptorImageInfo imageInfo =
885 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
887 const VkWriteDescriptorSet descriptorWrite =
889 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
891 *m_extraResourcesSet,
893 0u, // dstArrayElement
895 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
897 (const VkDescriptorBufferInfo*)DE_NULL,
898 (const VkBufferView*)DE_NULL,
901 vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
904 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_context, m_shaderType, m_shaderSpec, *m_extraResourcesLayout));
907 VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams)
909 VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
911 if (samplerParams.minFilter == VK_FILTER_LINEAR ||
912 samplerParams.magFilter == VK_FILTER_LINEAR ||
913 samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
915 features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
921 bool TextureFilteringTestInstance::isSupported (void)
923 const VkImageCreateFlags imCreateFlags = (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
924 const VkFormatFeatureFlags reqImFeatures = getRequiredFormatFeatures(m_samplerParams);
926 const VkImageFormatProperties imFormatProperties = getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(),
927 m_context.getPhysicalDevice(),
929 mapImageType(m_imParams.dim),
930 VK_IMAGE_TILING_OPTIMAL,
931 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
933 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(),
934 m_context.getPhysicalDevice(),
937 // \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties
938 DE_UNREF(imFormatProperties);
940 return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures;
943 class TextureFilteringTestCase : public TestCase
946 TextureFilteringTestCase (tcu::TestContext& testCtx,
948 const char* description)
949 : TestCase(testCtx, name, description)
953 void initSpec (void);
955 virtual void initPrograms (vk::SourceCollections& programCollection) const
957 generateSources(m_testCaseData.shaderType, m_shaderSpec, programCollection);
960 virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0;
962 virtual TestInstance* createInstance (Context& ctx) const
964 return new TextureFilteringTestInstance(ctx, m_testCaseData, m_shaderSpec, createGenerator());
968 de::MovePtr<ShaderExecutor> m_executor;
969 TestCaseData m_testCaseData;
970 ShaderSpec m_shaderSpec;
973 void TextureFilteringTestCase::initSpec (void)
975 m_shaderSpec.source = genLookupCode(m_testCaseData.imParams,
976 m_testCaseData.samplerParams,
977 m_testCaseData.sampleLookupSettings);
978 m_shaderSpec.source += "\nsampledCoord = coord;";
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)));
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;";
995 class Texture2DGradientTestCase : public TextureFilteringTestCase
998 Texture2DGradientTestCase (TestContext& testCtx,
1001 TextureFormat format,
1005 VkSamplerMipmapMode mipmapFilter,
1006 VkSamplerAddressMode wrappingMode,
1007 bool useDerivatives)
1009 : TextureFilteringTestCase (testCtx, name, desc)
1011 , m_dimensions (dimensions)
1012 , m_magFilter (magFilter)
1013 , m_minFilter (minFilter)
1014 , m_mipmapFilter (mipmapFilter)
1015 , m_wrappingMode (wrappingMode)
1016 , m_useDerivatives (useDerivatives)
1018 m_testCaseData = genTestCaseData();
1025 virtual de::MovePtr<DataGenerator> createGenerator (void) const;
1027 TestCaseData genTestCaseData()
1031 const SampleLookupSettings sampleLookupSettings =
1033 m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
1034 false, // hasLodBias
1035 false, // isProjective
1038 const SamplerParameters samplerParameters =
1046 VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1054 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0],
1057 const ImageViewParameters imParameters =
1060 mapTextureFormat(m_format),
1067 const TestCaseData data =
1069 std::vector<ConstPixelBufferAccess>(),
1072 sampleLookupSettings,
1073 glu::SHADERTYPE_FRAGMENT
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;
1089 class Texture2DGradientTestCase::Generator : public DataGenerator
1092 Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {}
1094 virtual ~Generator (void)
1096 delete m_tex.release();
1099 virtual bool generate (void)
1101 m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format,
1102 m_testCase->m_dimensions[0],
1103 m_testCase->m_dimensions[1]));
1105 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0],
1106 m_testCase->m_dimensions[1])));
1108 const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format);
1110 const Vec4 cBias = fmtInfo.valueMin;
1111 const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
1113 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
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;
1118 m_tex->allocLevel(levelNdx);
1119 fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax);
1125 virtual std::vector<ConstPixelBufferAccess> getPba (void) const
1127 std::vector<ConstPixelBufferAccess> pba;
1129 const deUint8 numLevels = (deUint8) m_tex->getNumLevels();
1131 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1133 pba.push_back(m_tex->getLevel(levelNdx));
1139 virtual std::vector<SampleArguments> getSampleArgs (void) const
1141 std::vector<SampleArguments> args;
1143 if (m_testCase->m_useDerivatives)
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)}
1159 for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1161 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1163 for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
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]),
1169 cur.dPdx = derivativePairs[derivNdx].dPdx;
1170 cur.dPdy = derivativePairs[derivNdx].dPdy;
1172 args.push_back(cur);
1179 const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
1181 for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1183 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1185 for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
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]),
1191 cur.lod = lodList[lodNdx];
1193 args.push_back(cur);
1203 const Texture2DGradientTestCase* m_testCase;
1204 de::MovePtr<Texture2D> m_tex;
1207 de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const
1209 return de::MovePtr<DataGenerator>(new Generator(this));
1212 TestCaseGroup* create2DFormatTests (TestContext& testCtx)
1214 de::MovePtr<TestCaseGroup> tests(
1215 new TestCaseGroup(testCtx, "formats", "Various image formats"));
1217 const VkFormat formats[] =
1219 VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1220 VK_FORMAT_R5G6B5_UNORM_PACK16,
1221 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
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
1245 const IVec3 size(32, 32, 1);
1247 for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
1249 const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
1251 Texture2DGradientTestCase* testCaseNearest =
1252 new Texture2DGradientTestCase(
1254 (prefix + "_nearest").c_str(),
1256 mapVkFormat(formats[formatNdx]),
1260 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1261 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1264 tests->addChild(testCaseNearest);
1266 Texture2DGradientTestCase* testCaseLinear =
1267 new Texture2DGradientTestCase(
1269 (prefix + "_linear").c_str(),
1271 mapVkFormat(formats[formatNdx]),
1275 VK_SAMPLER_MIPMAP_MODE_LINEAR,
1276 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1279 tests->addChild(testCaseLinear);
1282 return tests.release();
1285 TestCaseGroup* create2DDerivTests (TestContext& testCtx)
1287 de::MovePtr<TestCaseGroup> tests(
1288 new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
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);
1294 const VkFilter filters[2] =
1300 const VkSamplerMipmapMode mipmapFilters[2] =
1302 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1303 VK_SAMPLER_MIPMAP_MODE_LINEAR,
1306 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
1308 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
1310 for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
1312 std::ostringstream caseName;
1314 switch (filters[magFilterNdx])
1316 case VK_FILTER_NEAREST:
1317 caseName << "nearest";
1320 case VK_FILTER_LINEAR:
1321 caseName << "linear";
1328 switch (filters[minFilterNdx])
1330 case VK_FILTER_NEAREST:
1331 caseName << "_nearest";
1334 case VK_FILTER_LINEAR:
1335 caseName << "_linear";
1342 caseName << "_mipmap";
1344 switch (mipmapFilters[mipmapFilterNdx])
1346 case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1347 caseName << "_nearest";
1350 case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1351 caseName << "_linear";
1358 Texture2DGradientTestCase* testCase =
1359 new Texture2DGradientTestCase(
1361 caseName.str().c_str(),
1363 mapVkFormat(format),
1365 filters[magFilterNdx],
1366 filters[minFilterNdx],
1367 mipmapFilters[mipmapFilterNdx],
1371 tests->addChild(testCase);
1376 return tests.release();
1379 TestCaseGroup* create2DSizeTests (TestContext& testCtx)
1381 de::MovePtr<TestCaseGroup> tests(
1382 new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations"));
1384 const VkFilter filters[2] =
1390 const VkSamplerMipmapMode mipmapFilters[2] =
1392 VK_SAMPLER_MIPMAP_MODE_NEAREST,
1393 VK_SAMPLER_MIPMAP_MODE_LINEAR
1396 const VkSamplerAddressMode wrappingModes[2] =
1398 VK_SAMPLER_ADDRESS_MODE_REPEAT,
1399 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
1402 const IVec3 sizes[] =
1416 for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1418 for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx)
1420 for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx)
1422 for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx)
1424 for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx)
1426 std::ostringstream caseName;
1428 caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1];
1430 switch (filters[magFilterNdx])
1432 case VK_FILTER_NEAREST:
1433 caseName << "_nearest";
1436 case VK_FILTER_LINEAR:
1437 caseName << "_linear";
1444 switch (filters[minFilterNdx])
1446 case VK_FILTER_NEAREST:
1447 caseName << "_nearest";
1450 case VK_FILTER_LINEAR:
1451 caseName << "_linear";
1458 switch (mipmapFilters[mipmapFilterNdx])
1460 case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1461 caseName << "_mipmap_nearest";
1464 case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1465 caseName << "_mipmap_linear";
1472 switch (wrappingModes[wrappingModeNdx])
1474 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1475 caseName << "_clamp";
1478 case VK_SAMPLER_ADDRESS_MODE_REPEAT:
1479 caseName << "_repeat";
1486 Texture2DGradientTestCase* testCase =
1487 new Texture2DGradientTestCase(
1489 caseName.str().c_str(),
1491 mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM),
1493 filters[magFilterNdx],
1494 filters[minFilterNdx],
1495 mipmapFilters[mipmapFilterNdx],
1496 wrappingModes[wrappingModeNdx],
1499 tests->addChild(testCase);
1506 return tests.release();
1509 TestCaseGroup* create2DTests (TestContext& testCtx)
1511 de::MovePtr<TestCaseGroup> tests(
1512 new TestCaseGroup(testCtx, "2d", "2D Image filtering tests"));
1514 tests->addChild(create2DSizeTests(testCtx));
1515 tests->addChild(create2DFormatTests(testCtx));
1516 tests->addChild(create2DDerivTests(testCtx));
1518 return tests.release();
1523 TestCaseGroup* createExplicitLodTests (TestContext& testCtx)
1525 de::MovePtr<TestCaseGroup> tests(
1526 new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD"));
1528 tests->addChild(create2DTests(testCtx));
1530 return tests.release();